OSDN Git Service

Don't use safe_new but new throughout. Fix copyright dates
authorcorinna <corinna>
Wed, 19 Nov 2003 18:49:40 +0000 (18:49 +0000)
committercorinna <corinna>
Wed, 19 Nov 2003 18:49:40 +0000 (18:49 +0000)
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.

27 files changed:
winsup/cygserver/ChangeLog
winsup/cygserver/Makefile.in
winsup/cygserver/bsd_helper.cc [new file with mode: 0644]
winsup/cygserver/bsd_helper.h [new file with mode: 0644]
winsup/cygserver/bsd_log.cc [new file with mode: 0644]
winsup/cygserver/bsd_log.h [new file with mode: 0644]
winsup/cygserver/bsd_mutex.cc [new file with mode: 0644]
winsup/cygserver/bsd_mutex.h [new file with mode: 0644]
winsup/cygserver/client.cc
winsup/cygserver/cygserver.cc
winsup/cygserver/cygserver.conf [new file with mode: 0644]
winsup/cygserver/msg.cc
winsup/cygserver/process.cc
winsup/cygserver/process.h [moved from winsup/cygserver/cygserver_process.h with 96% similarity]
winsup/cygserver/sem.cc
winsup/cygserver/shm.cc
winsup/cygserver/sysv_msg.cc [new file with mode: 0644]
winsup/cygserver/sysv_sem.cc [new file with mode: 0644]
winsup/cygserver/sysv_shm.cc [new file with mode: 0644]
winsup/cygserver/threaded_queue.cc
winsup/cygserver/transport.cc
winsup/cygserver/transport.h [moved from winsup/cygserver/cygserver_transport.h with 75% similarity]
winsup/cygserver/transport_pipes.cc
winsup/cygserver/transport_pipes.h [moved from winsup/cygserver/cygserver_transport_pipes.h with 67% similarity]
winsup/cygserver/transport_sockets.cc
winsup/cygserver/transport_sockets.h [moved from winsup/cygserver/cygserver_transport_sockets.h with 86% similarity]
winsup/cygserver/woutsup.h

index cb76730..5b9dd13 100644 (file)
@@ -1,3 +1,76 @@
+2003-11-19  Corinna Vinschen  <corinna@vinschen.de>
+
+       Don't use safe_new but new throughout.  Fix copyright dates
+       throughout.
+       * Makefile.in: Accomodate all new files and name changes.
+       Add a *.d dependency.
+       (sbindir): Add.
+       (etcdir): Drop in favor of more appropriate sysconfdir definition.
+       (sysconfdir): Add.
+       (CXXFLAGS): Add -MMD flag. Add SYSCONFDIR definition.
+       (.SUFFIXES): Add.
+       (install): Add action items.
+       (libclean): New target.
+       (fullclean): Ditto.
+       * bsd_helper.cc: New file.
+       * bsd_helper.h: Ditto.
+       * bsd_log.cc: Ditto.
+       * bsd_log.h: Ditto.
+       * bsd_mutex.cc: Ditto.
+       * bsd_mutex.h: Ditto.
+       * client.cc: Rearrange to build as less as possible if
+       __INSIDE_CYGWIN__.
+       (client_request::handle_request): Add Message Queue and Semaphore
+       handling.
+       * cygserver.cc: Rearrange to build as less as possible if
+       __INSIDE_CYGWIN__. Use new debug/log/panic logging functions.
+       (DEF_CONFIG_FILE): New definition for configuration file.  Use
+       throughout.
+       (getfunc): Remove.
+       (__cygserver__printf): Remove.
+       (client_request_attach_tty::serve): Return error if impersonation
+       fails.
+       (print_usage): Pump up help message.
+       (print_version): Add output of default configuration file.
+       (main): Accommodate new options.  Allow overwrite of threading options
+       from config file.  Call several new initialization functions.  Drop
+       printing dots.  Don't define SIGHANDLE inline.
+       * cygserver.conf: New file.
+       * cygserver_process.h: Rename to process.h.
+       * cygserver_transport.h: Rename to transport.h.
+       * cygserver_transport_pipes.h: Rename to transport_pipes.h.
+       * cygserver_transport_sockets.h: Rename to transport_sockets.h.
+       * msg.cc: Rewrite.
+       * sem.cc: Rewrite.
+       * shm.cc: Rewrite.
+       * sysv_msg.cc: New file, derived from FreeBSD version 1.52.
+       * sysv_sem.cc: New file, derived from FreeBSD version 1.66.
+       * sysv_shm.cc: New file, derived from FreeBSD version 1.89.
+       * threaded_queue.cc: Rearrange to build as less as possible if
+       __INSIDE_CYGWIN__.
+       * transport.cc (transport_layer_base::impersonate_client): Define bool.
+       (transport_layer_base::revert_to_self): Ditto.
+       * transport.h (transport_layer_base::impersonate_client): Declare bool.
+       (transport_layer_base::revert_to_self): Ditto.
+       * transport_pipes.cc (transport_layer_pipes::transport_layer_pipes):
+       Don't call init_security.
+       (init_security): Remove.
+       (transport_layer_pipes::accept): Use global sec_all_nih.
+       (transport_layer_pipes::connect): Ditto.
+       (transport_layer_pipes::impersonate_client): Define bool.
+       (transport_layer_pipes::revert_to_self): Ditt.
+       * transport_pipes.h (transport_layer_pipes::impersonate_client): Declare
+       bool.
+       (transport_layer_pipes::revert_to_self): Ditto.
+       * woutsup.h: Include bsd compatibility headers.
+       (SIGHANDLE): Add definition.
+       (__cygserver__printf): Remove definition.
+       (__noop_printf): Ditto.
+       (debug_printf): Define using debug.
+       (syscall_printf): Define using log.
+       (system_printf): Ditto.
+       Drop all other _printf definitions.
+
 2003-10-22  Corinna Vinschen  <corinna@vinschen.de>
 
        Accomodate moving cygserver header files from cygwin/include/cygwin
index 767fcaa..0dd1120 100644 (file)
@@ -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@
 
+include $(srcdir)/../Makefile.common
+
 CFLAGS:=@CFLAGS@ -I$(cygwin_source)
 CXXFLAGS:=@CXXFLAGS@ -I$(cygwin_source)
-override CXXFLAGS+=-fno-exceptions -fno-rtti -DHAVE_DECL_GETOPT=0 -D__OUTSIDE_CYGWIN__
+override CXXFLAGS+=-MMD -fno-exceptions -fno-rtti -DHAVE_DECL_GETOPT=0 -D__OUTSIDE_CYGWIN__ -DSYSCONFDIR="\"$(sysconfdir)\""
 
-include $(srcdir)/../Makefile.common
+.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
diff --git a/winsup/cygserver/bsd_helper.cc b/winsup/cygserver/bsd_helper.cc
new file mode 100644 (file)
index 0000000..42afd54
--- /dev/null
@@ -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__ */
diff --git a/winsup/cygserver/bsd_helper.h b/winsup/cygserver/bsd_helper.h
new file mode 100644 (file)
index 0000000..14849e9
--- /dev/null
@@ -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 */
diff --git a/winsup/cygserver/bsd_log.cc b/winsup/cygserver/bsd_log.cc
new file mode 100644 (file)
index 0000000..5cf1c84
--- /dev/null
@@ -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__ */
diff --git a/winsup/cygserver/bsd_log.h b/winsup/cygserver/bsd_log.h
new file mode 100644 (file)
index 0000000..4857318
--- /dev/null
@@ -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 */
diff --git a/winsup/cygserver/bsd_mutex.cc b/winsup/cygserver/bsd_mutex.cc
new file mode 100644 (file)
index 0000000..9c7485b
--- /dev/null
@@ -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__ */
diff --git a/winsup/cygserver/bsd_mutex.h b/winsup/cygserver/bsd_mutex.h
new file mode 100644 (file)
index 0000000..3b07bf3
--- /dev/null
@@ -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 */
index 600ddbd..d8f7ac5 100644 (file)
@@ -1,6 +1,6 @@
-/* cygserver_client.cc
+/* client.cc
 
-   Copyright 2001, 2002 Red Hat Inc.
+   Copyright 2001, 2002, 2003 Red Hat Inc.
 
    Written by Egor Duda <deo@logos-m.ru>
 
@@ -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
-}
-
-#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;
+  delete req;
 }
 
-#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__ */
index f152fc5..d38d12e 100644 (file)
@@ -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"
 
-// 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);
+#include "cygserver_ipc.h"
+#include "cygserver_msg.h"
+#include "cygserver_sem.h"
 
-  va_start (ap, fmt);
-  len += vsnprintf (buf + len, BUFSIZ - len, fmt, ap);
-  va_end (ap);
+#define DEF_CONFIG_FILE        "" SYSCONFDIR "/cygserver.conf"
 
-  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 */
+// Version string.
+static const char version[] = "$Revision$";
 
 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 *pgm = NULL;
-
-  if (!(pgm = strrchr (*argv, '\\')) && !(pgm = strrchr (*argv, '/')))
-    pgm = *argv;
+  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;
+
+  char *c = NULL;
+
+  /* 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__ */
diff --git a/winsup/cygserver/cygserver.conf b/winsup/cygserver/cygserver.conf
new file mode 100644 (file)
index 0000000..b7db6bb
--- /dev/null
@@ -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
index fecaa06..713a586 100644 (file)
@@ -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"
-
-#include <sys/types.h>
-#include <cygwin/msg.h>
+#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 "cygerrno.h"
-
-extern "C" int
-msgctl (int msqid, int cmd, struct msqid_ds *buf)
-{
-  set_errno (ENOSYS);
-  return -1;
-}
+#include "cygserver.h"
+#include "process.h"
+#include "transport.h"
 
-extern "C" int
-msgget (key_t key, int msgflg)
-{
-  set_errno (ENOSYS);
-  return -1;
-}
+#include "cygserver_ipc.h"
+#include "cygserver_msg.h"
 
-extern "C" ssize_t
-msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
-{
-  set_errno (ENOSYS);
-  return -1;
+client_request_msg::client_request_msg ()
+  : client_request (CYGSERVER_REQUEST_MSG,
+                   &_parameters, sizeof (_parameters))
+{ 
 }
 
-extern "C" int
-msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
+void
+client_request_msg::serve (transport_layer_base *const conn,
+                           process_cache *const cache)
 {
-  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__ */
index aa8294f..0f6e0cb 100644 (file)
@@ -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 *
similarity index 96%
rename from winsup/cygserver/cygserver_process.h
rename to winsup/cygserver/process.h
index 25c634e..142b363 100644 (file)
@@ -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 */
index 97d91a3..6a179b0 100644 (file)
@@ -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;
-}
-
-extern "C" int
-semget (key_t key, int nsems, int semflg)
-{
-  set_errno (ENOSYS);
-  return -1;
+client_request_sem::client_request_sem ()
+  : client_request (CYGSERVER_REQUEST_SEM,
+                   &_parameters, sizeof (_parameters))
+{ 
 }
 
-extern "C" int
-semop (int semid, struct sembuf *sops, size_t nsops)
+void
+client_request_sem::serve (transport_layer_base *const conn,
+                           process_cache *const cache)
 {
-  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__ */
index 50d2b6e..f73fd01 100644 (file)
@@ -1,9 +1,6 @@
-/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin.
+/* shm.cc: Single unix specification IPC interface for Cygwin.
 
-   Copyright 2002 Red Hat, Inc.
-
-   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_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;
+#include "process.h"
+#include "transport.h"
 
-    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 ()
- *---------------------------------------------------------------------------*/
+#include "cygserver_ipc.h"
+#include "cygserver_shm.h"
 
 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 ();
+      error_code (EACCES);
+      msglen (0);
+      return;
     }
-
-  client->release ();
-  conn->revert_to_self ();
-
-  if (result < 0)
+  if (!adjust_identity_info (&_parameters.in.ipcblk))
     {
-      error_code (-result);
+      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__ */
diff --git a/winsup/cygserver/sysv_msg.cc b/winsup/cygserver/sysv_msg.cc
new file mode 100644 (file)
index 0000000..9c1049c
--- /dev/null
@@ -0,0 +1,1208 @@
+/*
+ * Implementation of SVID messages
+ *
+ * Author:  Daniel Boulet
+ *
+ * Copyright 1993 Daniel Boulet and RTMX Inc.
+ *
+ * This system call was implemented by Daniel Boulet under contract from RTMX.
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ */
+
+/*
+ * This file is heavily changed to become part of Cygwin's cygserver.
+ */
+
+#ifdef __OUTSIDE_CYGWIN__
+#include "woutsup.h"
+#include <sys/cdefs.h>
+#ifndef __FBSDID
+#define __FBSDID(s)    const char version[] = (s)
+#endif
+__FBSDID("$FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/kern/sysv_msg.c,v 1.52 2003/11/07 04:47:14 rwatson Exp $");
+
+#define _KERNEL 1
+#define __BSD_VISIBLE 1
+#include <sys/types.h>
+#include <sys/sysproto.h>
+#include <sys/ipc.h>
+#include <sys/param.h>
+#include <sys/msg.h>
+#include <malloc.h>
+#include <errno.h>
+#include <time.h>
+#include "cygserver.h"
+#include "process.h"
+#include "cygserver_ipc.h"
+
+#ifdef __CYGWIN__
+#define MSG_DEBUG
+#endif /* __CYGWIN__ */
+
+#ifdef MSG_DEBUG
+#define DPRINTF(a)     debug_printf a
+#else
+#define DPRINTF(a)
+#endif
+
+static void msg_freehdr(struct msg *msghdr);
+
+#ifndef __CYGWIN__
+int msgctl(struct thread *, struct msgctl_args *);
+int msgget(struct thread *, struct msgget_args *);
+int msgsnd(struct thread *, struct msgsnd_args *);
+int msgrcv(struct thread *, struct msgrcv_args *);
+
+static sy_call_t *msgcalls[] = {
+       (sy_call_t *)msgctl, (sy_call_t *)msgget,
+       (sy_call_t *)msgsnd, (sy_call_t *)msgrcv
+};
+#endif /* __CYGWIN__ */
+
+
+struct msg {
+       struct  msg *msg_next;  /* next msg in the chain */
+       long    msg_type;       /* type of this message */
+                               /* >0 -> type of this message */
+                               /* 0 -> free header */
+       u_short msg_ts;         /* size of this message */
+       short   msg_spot;       /* location of start of msg in buffer */
+};
+
+
+#ifndef MSGSSZ
+#define MSGSSZ 8               /* Each segment must be 2^N long */
+#endif
+#ifndef MSGSEG
+#define MSGSEG 2048            /* must be less than 32767 */
+#endif
+#define MSGMAX (MSGSSZ*MSGSEG)
+#ifndef MSGMNB
+#define MSGMNB 2048            /* max # of bytes in a queue */
+#endif
+#ifndef MSGMNI
+#define MSGMNI 40
+#endif
+#ifndef MSGTQL
+#define MSGTQL 40
+#endif
+
+/*
+ * Based on the configuration parameters described in an SVR2 (yes, two)
+ * config(1m) man page.
+ *
+ * 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.
+ * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
+ * two between 8 and 1024 inclusive (and panic's if it isn't).
+ */
+struct msginfo msginfo = {
+                MSGMAX,         /* max chars in a message */
+                MSGMNB,         /* max chars in a queue */
+                MSGMNI,         /* # of message queue identifiers */
+                MSGTQL,         /* max messages in system */
+                MSGSSZ,         /* size of a message segment */
+                               /* (must be small power of 2 greater than 4) */
+                MSGSEG          /* number of message segments */
+};
+
+/*
+ * macros to convert between msqid_ds's and msqid's.
+ * (specific to this implementation)
+ */
+#define MSQID(ix,ds)   ((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
+#define MSQID_IX(id)   ((id) & 0xffff)
+#define MSQID_SEQ(id)  (((id) >> 16) & 0xffff)
+
+/*
+ * The rest of this file is specific to this particular implementation.
+ */
+
+struct msgmap {
+       short   next;           /* next segment in buffer */
+                               /* -1 -> available */
+                               /* 0..(MSGSEG-1) -> index of next segment */
+};
+
+#define MSG_LOCKED     01000   /* Is this msqid_ds locked? */
+
+static int nfree_msgmaps;      /* # of free map entries */
+static short free_msgmaps;     /* head of linked list of free map entries */
+static struct msg *free_msghdrs;/* list of free msg headers */
+static char *msgpool;          /* MSGMAX byte long msg buffer pool */
+static struct msgmap *msgmaps; /* MSGSEG msgmap structures */
+static struct msg *msghdrs;    /* MSGTQL msg headers */
+static struct msqid_ds *msqids;        /* MSGMNI msqid_ds struct's */
+static struct mtx msq_mtx;     /* global mutex for message queues. */
+
+#ifdef __CYGWIN__
+static struct msg_info msg_info;
+#endif /* __CYGWIN__ */
+
+void
+msginit()
+{
+       int i;
+
+       TUNABLE_INT_FETCH("kern.ipc.msgseg", &msginfo.msgseg);
+       TUNABLE_INT_FETCH("kern.ipc.msgssz", &msginfo.msgssz);
+       msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
+       TUNABLE_INT_FETCH("kern.ipc.msgmni", &msginfo.msgmni);
+
+       msgpool = (char *) sys_malloc(msginfo.msgmax, M_MSG, M_WAITOK);
+       if (msgpool == NULL)
+               panic("msgpool is NULL");
+       msgmaps = (msgmap *) sys_malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
+       if (msgmaps == NULL)
+               panic("msgmaps is NULL");
+       msghdrs = (msg *) sys_malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
+       if (msghdrs == NULL)
+               panic("msghdrs is NULL");
+       msqids = (msqid_ds *) sys_malloc(sizeof(struct msqid_ds) * msginfo.msgmni, M_MSG, M_WAITOK);
+       if (msqids == NULL)
+               panic("msqids is NULL");
+
+       /*
+        * msginfo.msgssz should be a power of two for efficiency reasons.
+        * It is also pretty silly if msginfo.msgssz is less than 8
+        * or greater than about 256 so ...
+        */
+
+       i = 8;
+       while (i < 1024 && i != msginfo.msgssz)
+               i <<= 1;
+       if (i != msginfo.msgssz) {
+               DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
+                   msginfo.msgssz));
+               panic("msginfo.msgssz not a small power of 2");
+       }
+
+       if (msginfo.msgseg > 32767) {
+               DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
+               panic("msginfo.msgseg > 32767");
+       }
+
+       if (msgmaps == NULL)
+               panic("msgmaps is NULL");
+
+       for (i = 0; i < msginfo.msgseg; i++) {
+               if (i > 0)
+                       msgmaps[i-1].next = i;
+               msgmaps[i].next = -1;   /* implies entry is available */
+       }
+       free_msgmaps = 0;
+       nfree_msgmaps = msginfo.msgseg;
+
+       if (msghdrs == NULL)
+               panic("msghdrs is NULL");
+
+       for (i = 0; i < msginfo.msgtql; i++) {
+               msghdrs[i].msg_type = 0;
+               if (i > 0)
+                       msghdrs[i-1].msg_next = &msghdrs[i];
+               msghdrs[i].msg_next = NULL;
+       }
+       free_msghdrs = &msghdrs[0];
+
+       if (msqids == NULL)
+               panic("msqids is NULL");
+
+       for (i = 0; i < msginfo.msgmni; i++) {
+               msqids[i].msg_qbytes = 0;       /* implies entry is available */
+               msqids[i].msg_perm.seq = 0;     /* reset to a known value */
+               msqids[i].msg_perm.mode = 0;
+       }
+       mtx_init(&msq_mtx, "msq", NULL, MTX_DEF);
+}
+
+int
+msgunload()
+{
+       struct msqid_ds *msqptr;
+       int msqid;
+
+       for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
+               /*
+                * Look for an unallocated and unlocked msqid_ds.
+                * msqid_ds's can be locked by msgsnd or msgrcv while
+                * they are copying the message in/out.  We can't
+                * re-use the entry until they release it.
+                */
+               msqptr = &msqids[msqid];
+               if (msqptr->msg_qbytes != 0 ||
+                   (msqptr->msg_perm.mode & MSG_LOCKED) != 0)
+                       break;
+       }
+#ifndef __CYGWIN__
+       if (msqid != msginfo.msgmni)
+               return (EBUSY);
+#endif /* __CYGWIN__ */
+
+       sys_free(msgpool, M_MSG);
+       sys_free(msgmaps, M_MSG);
+       sys_free(msghdrs, M_MSG);
+       sys_free(msqids, M_MSG);
+       mtx_destroy(&msq_mtx);
+       return (0);
+}
+
+
+#ifndef __CYGWIN__
+static int
+sysvmsg_modload(struct module *module, int cmd, void *arg)
+{
+       int error = 0;
+
+       switch (cmd) {
+       case MOD_LOAD:
+               msginit();
+               break;
+       case MOD_UNLOAD:
+               error = msgunload();
+               break;
+       case MOD_SHUTDOWN:
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+       return (error);
+}
+
+static moduledata_t sysvmsg_mod = {
+       "sysvmsg",
+       &sysvmsg_modload,
+       NULL
+};
+
+SYSCALL_MODULE_HELPER(msgsys);
+SYSCALL_MODULE_HELPER(msgctl);
+SYSCALL_MODULE_HELPER(msgget);
+SYSCALL_MODULE_HELPER(msgsnd);
+SYSCALL_MODULE_HELPER(msgrcv);
+
+DECLARE_MODULE(sysvmsg, sysvmsg_mod,
+       SI_SUB_SYSV_MSG, SI_ORDER_FIRST);
+MODULE_VERSION(sysvmsg, 1);
+
+/*
+ * Entry point for all MSG calls
+ *
+ * MPSAFE
+ */
+int
+msgsys(thread *td, struct msgsys_args *uap)
+{
+       int error;
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+       if (uap->which < 0 ||
+           (unsigned) uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
+               return (EINVAL);
+       error = (*msgcalls[uap->which])(td, &uap->a2);
+       return (error);
+}
+#endif
+
+static void
+msg_freehdr(struct msg *msghdr)
+{
+       while (msghdr->msg_ts > 0) {
+               short next;
+               if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
+                       panic("msghdr->msg_spot out of range");
+               next = msgmaps[msghdr->msg_spot].next;
+               msgmaps[msghdr->msg_spot].next = free_msgmaps;
+               free_msgmaps = msghdr->msg_spot;
+               nfree_msgmaps++;
+               msghdr->msg_spot = next;
+               if (msghdr->msg_ts >= msginfo.msgssz)
+                       msghdr->msg_ts -= msginfo.msgssz;
+               else
+                       msghdr->msg_ts = 0;
+       }
+       if (msghdr->msg_spot != -1)
+               panic("msghdr->msg_spot != -1");
+       msghdr->msg_next = free_msghdrs;
+       free_msghdrs = msghdr;
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct msgctl_args {
+       int     msqid;
+       int     cmd;
+       struct  msqid_ds *buf;
+};
+#endif
+
+/*
+ * MPSAFE
+ */
+int
+msgctl(struct thread *td, struct msgctl_args *uap)
+{
+       int msqid = uap->msqid;
+       int cmd = uap->cmd;
+       struct msqid_ds *user_msqptr = uap->buf;
+       int rval, error;
+       struct msqid_ds msqbuf;
+       register struct msqid_ds *msqptr;
+
+       DPRINTF(("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr));
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+
+#ifdef __CYGWIN__
+       if (cmd == IPC_INFO) {
+               if (!msqid) {
+                       error = copyout(&msginfo, user_msqptr,
+                                       sizeof(struct msginfo));
+                       td->td_retval[0] = error ? -1 : 0;
+                       return (error);
+               }
+               if (msqid > msginfo.msgmni)
+                       msqid = msginfo.msgmni;
+               error = copyout(msqids, user_msqptr,
+                               msqid * sizeof(struct msqid_ds));
+               td->td_retval[0] = error ? -1 : 0;
+               return (error);
+       } else if (cmd == MSG_INFO) {
+               mtx_lock(&msq_mtx);
+               error = copyout(&msg_info, user_msqptr,
+                               sizeof(struct msg_info));
+               td->td_retval[0] = error ? -1 : 0;
+               mtx_unlock(&msq_mtx);
+               return (error);
+       }
+#endif /* __CYGWIN__ */
+       msqid = IPCID_TO_IX(msqid);
+
+       if (msqid < 0 || msqid >= msginfo.msgmni) {
+               DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
+                   msginfo.msgmni));
+               return (EINVAL);
+       }
+       if (cmd == IPC_SET &&
+           (error = copyin(user_msqptr, &msqbuf, sizeof(msqbuf))) != 0)
+               return (error);
+
+       msqptr = &msqids[msqid];
+
+       mtx_lock(&msq_mtx);
+       if (msqptr->msg_qbytes == 0) {
+               DPRINTF(("no such msqid\n"));
+               error = EINVAL;
+               goto done2;
+       }
+       if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
+               DPRINTF(("wrong sequence number\n"));
+               error = EINVAL;
+               goto done2;
+       }
+
+       error = 0;
+       rval = 0;
+
+       switch (cmd) {
+
+       case IPC_RMID:
+       {
+               struct msg *msghdr;
+               if ((error = ipcperm(td, &msqptr->msg_perm, IPC_M)))
+                       goto done2;
+               /* Free the message headers */
+               msghdr = msqptr->msg_first;
+               while (msghdr != NULL) {
+                       struct msg *msghdr_tmp;
+
+                       /* Free the segments of each message */
+                       msqptr->msg_cbytes -= msghdr->msg_ts;
+                       msqptr->msg_qnum--;
+                       msghdr_tmp = msghdr;
+                       msghdr = msghdr->msg_next;
+                       msg_freehdr(msghdr_tmp);
+               }
+
+               if (msqptr->msg_cbytes != 0)
+                       panic("msg_cbytes is screwed up");
+               if (msqptr->msg_qnum != 0)
+                       panic("msg_qnum is screwed up");
+
+               msqptr->msg_qbytes = 0; /* Mark it as free */
+#ifdef __CYGWIN__
+               msg_info.msg_ids--;
+#endif /* __CYGWIN__ */
+
+               wakeup(msqptr);
+       }
+
+               break;
+
+       case IPC_SET:
+               if ((error = ipcperm(td, &msqptr->msg_perm, IPC_M)))
+                       goto done2;
+               if (msqbuf.msg_qbytes > msqptr->msg_qbytes) {
+                       error = suser(td);
+                       if (error)
+                               goto done2;
+               }
+               if (msqbuf.msg_qbytes > (unsigned long) msginfo.msgmnb) {
+                       DPRINTF(("can't increase msg_qbytes beyond %d"
+                           "(truncating)\n", msginfo.msgmnb));
+                       msqbuf.msg_qbytes = msginfo.msgmnb;     /* silently restrict qbytes to system limit */
+               }
+               if (msqbuf.msg_qbytes == 0) {
+                       DPRINTF(("can't reduce msg_qbytes to 0\n"));
+                       error = EINVAL;         /* non-standard errno! */
+                       goto done2;
+               }
+               msqptr->msg_perm.uid = msqbuf.msg_perm.uid;     /* change the owner */
+               msqptr->msg_perm.gid = msqbuf.msg_perm.gid;     /* change the owner */
+               msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
+                   (msqbuf.msg_perm.mode & 0777);
+               msqptr->msg_qbytes = msqbuf.msg_qbytes;
+               msqptr->msg_ctime = time (NULL);
+               break;
+
+       case IPC_STAT:
+               if ((error = ipcperm(td, &msqptr->msg_perm, IPC_R))) {
+                       DPRINTF(("requester doesn't have read access\n"));
+                       goto done2;
+               }
+               break;
+
+       default:
+               DPRINTF(("invalid command %d\n", cmd));
+               error = EINVAL;
+               goto done2;
+       }
+
+       if (error == 0)
+               td->td_retval[0] = rval;
+done2:
+       mtx_unlock(&msq_mtx);
+       if (cmd == IPC_STAT && error == 0)
+               error = copyout(msqptr, user_msqptr, sizeof(struct msqid_ds));
+       return(error);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct msgget_args {
+       key_t   key;
+       int     msgflg;
+};
+#endif
+
+/*
+ * MPSAFE
+ */
+int
+msgget(struct thread *td, struct msgget_args *uap)
+{
+       int msqid, error = 0;
+       key_t key = uap->key;
+       unsigned msgflg = uap->msgflg;
+       register struct msqid_ds *msqptr = NULL;
+
+       DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+
+       mtx_lock(&msq_mtx);
+       if (key != IPC_PRIVATE) {
+               for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
+                       msqptr = &msqids[msqid];
+                       if (msqptr->msg_qbytes != 0 &&
+                           msqptr->msg_perm.key == key)
+                               break;
+               }
+               if (msqid < msginfo.msgmni) {
+                       DPRINTF(("found public key\n"));
+                       if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
+                               DPRINTF(("not exclusive\n"));
+                               error = EEXIST;
+                               goto done2;
+                       }
+                       if ((error = ipcperm(td, &msqptr->msg_perm, msgflg & 0700))) {
+                               DPRINTF(("requester doesn't have 0%o access\n",
+                                   msgflg & 0700));
+                               goto done2;
+                       }
+                       goto found;
+               }
+       }
+
+       DPRINTF(("need to allocate the msqid_ds\n"));
+       if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
+               for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
+                       /*
+                        * Look for an unallocated and unlocked msqid_ds.
+                        * msqid_ds's can be locked by msgsnd or msgrcv while
+                        * they are copying the message in/out.  We can't
+                        * re-use the entry until they release it.
+                        */
+                       msqptr = &msqids[msqid];
+                       if (msqptr->msg_qbytes == 0 &&
+                           (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
+                               break;
+               }
+               if (msqid == msginfo.msgmni) {
+                       DPRINTF(("no more msqid_ds's available\n"));
+                       error = ENOSPC;
+                       goto done2;
+               }
+               DPRINTF(("msqid %d is available\n", msqid));
+               msqptr->msg_perm.key = key;
+#ifdef __CYGWIN__
+               msqptr->msg_perm.cuid = td->ipcblk->uid;
+               msqptr->msg_perm.uid = td->ipcblk->uid;
+               msqptr->msg_perm.cgid = td->ipcblk->gid;
+               msqptr->msg_perm.gid = td->ipcblk->gid;
+#else
+               msqptr->msg_perm.cuid = cred->cr_uid;
+               msqptr->msg_perm.uid = cred->cr_uid;
+               msqptr->msg_perm.cgid = cred->cr_gid;
+               msqptr->msg_perm.gid = cred->cr_gid;
+#endif /* __CYGWIN__ */
+               msqptr->msg_perm.mode = (msgflg & 0777);
+               /* Make sure that the returned msqid is unique */
+               msqptr->msg_perm.seq = (msqptr->msg_perm.seq + 1) & 0x7fff;
+               msqptr->msg_first = NULL;
+               msqptr->msg_last = NULL;
+               msqptr->msg_cbytes = 0;
+               msqptr->msg_qnum = 0;
+               msqptr->msg_qbytes = msginfo.msgmnb;
+               msqptr->msg_lspid = 0;
+               msqptr->msg_lrpid = 0;
+               msqptr->msg_stime = 0;
+               msqptr->msg_rtime = 0;
+               msqptr->msg_ctime = time (NULL);
+#ifdef __CYGWIN__
+               msg_info.msg_ids++;
+#endif /* __CYGWIN__ */
+       } else {
+               DPRINTF(("didn't find it and wasn't asked to create it\n"));
+               error = ENOENT;
+               goto done2;
+       }
+
+found:
+       /* Construct the unique msqid */
+       td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
+done2:
+       mtx_unlock(&msq_mtx);
+       return (error);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct msgsnd_args {
+       int     msqid;
+       const void      *msgp;
+       size_t  msgsz;
+       int     msgflg;
+};
+#endif
+
+/*
+ * MPSAFE
+ */
+int
+msgsnd(struct thread *td, struct msgsnd_args *uap)
+{
+       int msqid = uap->msqid;
+       const void *user_msgp = uap->msgp;
+       size_t msgsz = uap->msgsz;
+       int msgflg = uap->msgflg;
+       int segs_needed, error = 0;
+       register struct msqid_ds *msqptr;
+       register struct msg *msghdr;
+       short next;
+
+       DPRINTF(("call to msgsnd(%d, 0x%x, %d, %d)\n", msqid, user_msgp, msgsz,
+           msgflg));
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+
+       mtx_lock(&msq_mtx);
+       msqid = IPCID_TO_IX(msqid);
+
+       if (msqid < 0 || msqid >= msginfo.msgmni) {
+               DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
+                   msginfo.msgmni));
+               error = EINVAL;
+               goto done2;
+       }
+
+       msqptr = &msqids[msqid];
+       if (msqptr->msg_qbytes == 0) {
+               DPRINTF(("no such message queue id\n"));
+               error = EINVAL;
+               goto done2;
+       }
+       if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
+               DPRINTF(("wrong sequence number\n"));
+               error = EINVAL;
+               goto done2;
+       }
+
+       if ((error = ipcperm(td, &msqptr->msg_perm, IPC_W))) {
+               DPRINTF(("requester doesn't have write access\n"));
+               goto done2;
+       }
+
+       segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
+       DPRINTF(("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz,
+           segs_needed));
+       for (;;) {
+               int need_more_resources = 0;
+
+               /*
+                * check msgsz
+                * (inside this loop in case msg_qbytes changes while we sleep)
+                */
+
+               if (msgsz > msqptr->msg_qbytes) {
+                       DPRINTF(("msgsz > msqptr->msg_qbytes\n"));
+                       error = EINVAL;
+                       goto done2;
+               }
+
+               if (msqptr->msg_perm.mode & MSG_LOCKED) {
+                       DPRINTF(("msqid is locked\n"));
+                       need_more_resources = 1;
+               }
+               if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
+                       DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
+                       need_more_resources = 1;
+               }
+               if (segs_needed > nfree_msgmaps) {
+                       DPRINTF(("segs_needed > nfree_msgmaps\n"));
+                       need_more_resources = 1;
+               }
+               if (free_msghdrs == NULL) {
+                       DPRINTF(("no more msghdrs\n"));
+                       need_more_resources = 1;
+               }
+
+               if (need_more_resources) {
+                       int we_own_it;
+
+                       if ((msgflg & IPC_NOWAIT) != 0) {
+                               DPRINTF(("need more resources but caller "
+                                   "doesn't want to wait\n"));
+                               error = EAGAIN;
+                               goto done2;
+                       }
+
+                       if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
+                               DPRINTF(("we don't own the msqid_ds\n"));
+                               we_own_it = 0;
+                       } else {
+                               /* Force later arrivals to wait for our
+                                  request */
+                               DPRINTF(("we own the msqid_ds\n"));
+                               msqptr->msg_perm.mode |= MSG_LOCKED;
+                               we_own_it = 1;
+                       }
+                       DPRINTF(("goodnight\n"));
+                       error = msleep(msqptr, &msq_mtx, (PZERO - 4) | PCATCH,
+                           "msgwait", 0);
+                       DPRINTF(("good morning, error=%d\n", error));
+                       if (we_own_it)
+                               msqptr->msg_perm.mode &= ~MSG_LOCKED;
+                       if (error != 0) {
+                               DPRINTF(("msgsnd:  interrupted system call\n"));
+#ifdef __CYGWIN__
+                         if (error != EIDRM)
+#endif /* __CYGWIN__ */
+                               error = EINTR;
+                               goto done2;
+                       }
+
+                       /*
+                        * Make sure that the msq queue still exists
+                        */
+
+                       if (msqptr->msg_qbytes == 0) {
+                               DPRINTF(("msqid deleted\n"));
+                               error = EIDRM;
+                               goto done2;
+                       }
+
+               } else {
+                       DPRINTF(("got all the resources that we need\n"));
+                       break;
+               }
+       }
+
+       /*
+        * We have the resources that we need.
+        * Make sure!
+        */
+
+       if (msqptr->msg_perm.mode & MSG_LOCKED)
+               panic("msg_perm.mode & MSG_LOCKED");
+       if (segs_needed > nfree_msgmaps)
+               panic("segs_needed > nfree_msgmaps");
+       if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes)
+               panic("msgsz + msg_cbytes > msg_qbytes");
+       if (free_msghdrs == NULL)
+               panic("no more msghdrs");
+
+       /*
+        * Re-lock the msqid_ds in case we page-fault when copying in the
+        * message
+        */
+
+       if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
+               panic("msqid_ds is already locked");
+       msqptr->msg_perm.mode |= MSG_LOCKED;
+
+       /*
+        * Allocate a message header
+        */
+
+       msghdr = free_msghdrs;
+       free_msghdrs = msghdr->msg_next;
+       msghdr->msg_spot = -1;
+       msghdr->msg_ts = msgsz;
+
+       /*
+        * Allocate space for the message
+        */
+
+       while (segs_needed > 0) {
+               if (nfree_msgmaps <= 0)
+                       panic("not enough msgmaps");
+               if (free_msgmaps == -1)
+                       panic("nil free_msgmaps");
+               next = free_msgmaps;
+               if (next <= -1)
+                       panic("next too low #1");
+               if (next >= msginfo.msgseg)
+                       panic("next out of range #1");
+               DPRINTF(("allocating segment %d to message\n", next));
+               free_msgmaps = msgmaps[next].next;
+               nfree_msgmaps--;
+               msgmaps[next].next = msghdr->msg_spot;
+               msghdr->msg_spot = next;
+               segs_needed--;
+       }
+
+       /*
+        * Copy in the message type
+        */
+
+       mtx_unlock(&msq_mtx);
+       if ((error = copyin(user_msgp, &msghdr->msg_type,
+           sizeof(msghdr->msg_type))) != 0) {
+               mtx_lock(&msq_mtx);
+               DPRINTF(("error %d copying the message type\n", error));
+               msg_freehdr(msghdr);
+               msqptr->msg_perm.mode &= ~MSG_LOCKED;
+               wakeup(msqptr);
+               goto done2;
+       }
+       mtx_lock(&msq_mtx);
+       user_msgp = (const char *)user_msgp + sizeof(msghdr->msg_type);
+
+       /*
+        * Validate the message type
+        */
+
+       if (msghdr->msg_type < 1) {
+               msg_freehdr(msghdr);
+               msqptr->msg_perm.mode &= ~MSG_LOCKED;
+               wakeup(msqptr);
+               DPRINTF(("mtype (%d) < 1\n", msghdr->msg_type));
+               error = EINVAL;
+               goto done2;
+       }
+
+       /*
+        * Copy in the message body
+        */
+
+       next = msghdr->msg_spot;
+       while (msgsz > 0) {
+               size_t tlen;
+               if (msgsz > (unsigned long) msginfo.msgssz)
+                       tlen = msginfo.msgssz;
+               else
+                       tlen = msgsz;
+               if (next <= -1)
+                       panic("next too low #2");
+               if (next >= msginfo.msgseg)
+                       panic("next out of range #2");
+               mtx_unlock(&msq_mtx);
+               if ((error = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
+                   tlen)) != 0) {
+                       mtx_lock(&msq_mtx);
+                       DPRINTF(("error %d copying in message segment\n",
+                           error));
+                       msg_freehdr(msghdr);
+                       msqptr->msg_perm.mode &= ~MSG_LOCKED;
+                       wakeup(msqptr);
+                       goto done2;
+               }
+               mtx_lock(&msq_mtx);
+               msgsz -= tlen;
+               user_msgp = (const char *)user_msgp + tlen;
+               next = msgmaps[next].next;
+       }
+       if (next != -1)
+               panic("didn't use all the msg segments");
+
+       /*
+        * We've got the message.  Unlock the msqid_ds.
+        */
+
+       msqptr->msg_perm.mode &= ~MSG_LOCKED;
+
+       /*
+        * Make sure that the msqid_ds is still allocated.
+        */
+
+       if (msqptr->msg_qbytes == 0) {
+               msg_freehdr(msghdr);
+               wakeup(msqptr);
+               error = EIDRM;
+               goto done2;
+       }
+
+       /*
+        * Put the message into the queue
+        */
+
+       if (msqptr->msg_first == NULL) {
+               msqptr->msg_first = msghdr;
+               msqptr->msg_last = msghdr;
+       } else {
+               msqptr->msg_last->msg_next = msghdr;
+               msqptr->msg_last = msghdr;
+       }
+       msqptr->msg_last->msg_next = NULL;
+
+       msqptr->msg_cbytes += msghdr->msg_ts;
+       msqptr->msg_qnum++;
+       msqptr->msg_lspid = td->td_proc->p_pid;
+       msqptr->msg_stime = time (NULL);
+
+#ifdef __CYGWIN__
+       msg_info.msg_num++;
+       msg_info.msg_tot += uap->msgsz;
+#endif /* __CYGWIN__ */
+
+       wakeup(msqptr);
+       td->td_retval[0] = 0;
+done2:
+       mtx_unlock(&msq_mtx);
+       return (error);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct msgrcv_args {
+       int     msqid;
+       void    *msgp;
+       size_t  msgsz;
+       long    msgtyp;
+       int     msgflg;
+};
+#endif
+
+/*
+ * MPSAFE
+ */
+int
+msgrcv(struct thread *td, struct msgrcv_args *uap)
+{
+       int msqid = uap->msqid;
+       void *user_msgp = uap->msgp;
+       size_t msgsz = uap->msgsz;
+       long msgtyp = uap->msgtyp;
+       int msgflg = uap->msgflg;
+       size_t len;
+       register struct msqid_ds *msqptr;
+       register struct msg *msghdr;
+       int error = 0;
+       short next;
+
+       DPRINTF(("call to msgrcv(%d, 0x%x, %d, %ld, %d)\n", msqid, user_msgp,
+           msgsz, msgtyp, msgflg));
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+
+       msqid = IPCID_TO_IX(msqid);
+
+       if (msqid < 0 || msqid >= msginfo.msgmni) {
+               DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
+                   msginfo.msgmni));
+               return (EINVAL);
+       }
+
+       msqptr = &msqids[msqid];
+       mtx_lock(&msq_mtx);
+       if (msqptr->msg_qbytes == 0) {
+               DPRINTF(("no such message queue id\n"));
+               error = EINVAL;
+               goto done2;
+       }
+       if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
+               DPRINTF(("wrong sequence number\n"));
+               error = EINVAL;
+               goto done2;
+       }
+
+       if ((error = ipcperm(td, &msqptr->msg_perm, IPC_R))) {
+               DPRINTF(("requester doesn't have read access\n"));
+               goto done2;
+       }
+
+       msghdr = NULL;
+       while (msghdr == NULL) {
+               if (msgtyp == 0) {
+                       msghdr = msqptr->msg_first;
+                       if (msghdr != NULL) {
+                               if (msgsz < msghdr->msg_ts &&
+                                   (msgflg & MSG_NOERROR) == 0) {
+                                       DPRINTF(("first message on the queue "
+                                           "is too big (want %d, got %d)\n",
+                                           msgsz, msghdr->msg_ts));
+                                       error = E2BIG;
+                                       goto done2;
+                               }
+                               if (msqptr->msg_first == msqptr->msg_last) {
+                                       msqptr->msg_first = NULL;
+                                       msqptr->msg_last = NULL;
+                               } else {
+                                       msqptr->msg_first = msghdr->msg_next;
+                                       if (msqptr->msg_first == NULL)
+                                               panic("msg_first/last screwed up #1");
+                               }
+                       }
+               } else {
+                       struct msg *previous;
+                       struct msg **prev;
+
+                       previous = NULL;
+                       prev = &(msqptr->msg_first);
+                       while ((msghdr = *prev) != NULL) {
+                               /*
+                                * Is this message's type an exact match or is
+                                * this message's type less than or equal to
+                                * the absolute value of a negative msgtyp?
+                                * Note that the second half of this test can
+                                * NEVER be true if msgtyp is positive since
+                                * msg_type is always positive!
+                                */
+
+                               if (msgtyp == msghdr->msg_type ||
+                                   msghdr->msg_type <= -msgtyp) {
+                                       DPRINTF(("found message type %d, "
+                                           "requested %d\n",
+                                           msghdr->msg_type, msgtyp));
+                                       if (msgsz < msghdr->msg_ts &&
+                                           (msgflg & MSG_NOERROR) == 0) {
+                                               DPRINTF(("requested message "
+                                                   "on the queue is too big "
+                                                   "(want %d, got %d)\n",
+                                                   msgsz, msghdr->msg_ts));
+                                               error = E2BIG;
+                                               goto done2;
+                                       }
+                                       *prev = msghdr->msg_next;
+                                       if (msghdr == msqptr->msg_last) {
+                                               if (previous == NULL) {
+                                                       if (prev !=
+                                                           &msqptr->msg_first)
+                                                               panic("msg_first/last screwed up #2");
+                                                       msqptr->msg_first =
+                                                           NULL;
+                                                       msqptr->msg_last =
+                                                           NULL;
+                                               } else {
+                                                       if (prev ==
+                                                           &msqptr->msg_first)
+                                                               panic("msg_first/last screwed up #3");
+                                                       msqptr->msg_last =
+                                                           previous;
+                                               }
+                                       }
+                                       break;
+                               }
+                               previous = msghdr;
+                               prev = &(msghdr->msg_next);
+                       }
+               }
+
+               /*
+                * We've either extracted the msghdr for the appropriate
+                * message or there isn't one.
+                * If there is one then bail out of this loop.
+                */
+
+               if (msghdr != NULL)
+                       break;
+
+               /*
+                * Hmph!  No message found.  Does the user want to wait?
+                */
+
+               if ((msgflg & IPC_NOWAIT) != 0) {
+                       DPRINTF(("no appropriate message found (msgtyp=%d)\n",
+                           msgtyp));
+                       /* The SVID says to return ENOMSG. */
+                       error = ENOMSG;
+                       goto done2;
+               }
+
+               /*
+                * Wait for something to happen
+                */
+
+               DPRINTF(("msgrcv:  goodnight\n"));
+               error = msleep(msqptr, &msq_mtx, (PZERO - 4) | PCATCH,
+                   "msgwait", 0);
+               DPRINTF(("msgrcv:  good morning (error=%d)\n", error));
+
+               if (error != 0) {
+                       DPRINTF(("msgsnd:  interrupted system call\n"));
+#ifdef __CYGWIN__
+                   if (error != EIDRM)
+#endif /* __CYGWIN__ */
+                       error = EINTR;
+                       goto done2;
+               }
+
+               /*
+                * Make sure that the msq queue still exists
+                */
+
+               if (msqptr->msg_qbytes == 0 ||
+                   msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
+                       DPRINTF(("msqid deleted\n"));
+                       error = EIDRM;
+                       goto done2;
+               }
+       }
+
+       /*
+        * Return the message to the user.
+        *
+        * First, do the bookkeeping (before we risk being interrupted).
+        */
+
+       msqptr->msg_cbytes -= msghdr->msg_ts;
+       msqptr->msg_qnum--;
+       msqptr->msg_lrpid = td->td_proc->p_pid;
+       msqptr->msg_rtime = time (NULL);
+
+       /*
+        * Make msgsz the actual amount that we'll be returning.
+        * Note that this effectively truncates the message if it is too long
+        * (since msgsz is never increased).
+        */
+
+       DPRINTF(("found a message, msgsz=%d, msg_ts=%d\n", msgsz,
+           msghdr->msg_ts));
+       if (msgsz > msghdr->msg_ts)
+               msgsz = msghdr->msg_ts;
+
+       /*
+        * Return the type to the user.
+        */
+
+       mtx_unlock(&msq_mtx);
+       error = copyout(&(msghdr->msg_type), user_msgp,
+           sizeof(msghdr->msg_type));
+       mtx_lock(&msq_mtx);
+       if (error != 0) {
+               DPRINTF(("error (%d) copying out message type\n", error));
+               msg_freehdr(msghdr);
+               wakeup(msqptr);
+               goto done2;
+       }
+       user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
+
+       /*
+        * Return the segments to the user
+        */
+
+       next = msghdr->msg_spot;
+       for (len = 0; len < msgsz; len += msginfo.msgssz) {
+               size_t tlen;
+
+               if (msgsz - len > (unsigned long) msginfo.msgssz)
+                       tlen = msginfo.msgssz;
+               else
+                       tlen = msgsz - len;
+               if (next <= -1)
+                       panic("next too low #3");
+               if (next >= msginfo.msgseg)
+                       panic("next out of range #3");
+               mtx_unlock(&msq_mtx);
+               error = copyout(&msgpool[next * msginfo.msgssz],
+                   user_msgp, tlen);
+               mtx_lock(&msq_mtx);
+               if (error != 0) {
+                       DPRINTF(("error (%d) copying out message segment\n",
+                           error));
+                       msg_freehdr(msghdr);
+                       wakeup(msqptr);
+                       goto done2;
+               }
+               user_msgp = (char *)user_msgp + tlen;
+               next = msgmaps[next].next;
+       }
+
+       /*
+        * Done, return the actual number of bytes copied out.
+        */
+
+#ifdef __CYGWIN__
+       msg_info.msg_num--;
+       msg_info.msg_tot -= msgsz;
+#endif /* __CYGWIN__ */
+
+       msg_freehdr(msghdr);
+       wakeup(msqptr);
+       td->td_retval[0] = msgsz;
+done2:
+       mtx_unlock(&msq_mtx);
+       return (error);
+}
+
+#ifndef __CYGWIN__
+static int
+sysctl_msqids(SYSCTL_HANDLER_ARGS)
+{
+
+       return (SYSCTL_OUT(req, msqids,
+           sizeof(struct msqid_ds) * msginfo.msgmni));
+}
+
+SYSCTL_DECL(_kern_ipc);
+SYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &msginfo.msgmni, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RD, &msginfo.msgmnb, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RD, &msginfo.msgtql, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &msginfo.msgssz, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &msginfo.msgseg, 0, "");
+SYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLFLAG_RD,
+    NULL, 0, sysctl_msqids, "", "Message queue IDs");
+#endif /* __CYGWIN__ */
+#endif /* __OUTSIDE_CYGWIN__ */
diff --git a/winsup/cygserver/sysv_sem.cc b/winsup/cygserver/sysv_sem.cc
new file mode 100644 (file)
index 0000000..ac5efcd
--- /dev/null
@@ -0,0 +1,1323 @@
+/*
+ * Implementation of SVID semaphores
+ *
+ * Author:  Daniel Boulet
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ */
+
+/*
+ * This file is heavily changed to become part of Cygwin's cygserver.
+ */
+
+#ifdef __OUTSIDE_CYGWIN__
+#include "woutsup.h"
+#include <sys/cygwin.h>
+#include <sys/cdefs.h>
+#ifndef __FBSDID
+#define __FBSDID(s)    const char version[] = (s)
+#endif
+__FBSDID("$FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/kern/sysv_sem.c,v 1.66 2003/11/10 07:22:41 tjr Exp $");
+
+#define _KERNEL 1
+#define __BSD_VISIBLE 1
+#include <sys/types.h>
+#include <sys/ipc.h>
+
+#include <sys/param.h>
+#include <sys/sysproto.h>
+#include <sys/lock.h>
+#include <sys/sem.h>
+#include <sys/queue.h>
+#include <malloc.h>
+#include <errno.h>
+#include <time.h>
+#include "cygserver.h"
+#include "process.h"
+#include "cygserver_ipc.h"
+
+#ifdef __CYGWIN__
+#define __semctl semctl
+#define __semctl_args semctl_args
+#define SEM_DEBUG
+#endif /* __CYGWIN__ */
+
+#ifdef SEM_DEBUG
+#define DPRINTF(a)     debug_printf a
+#else
+#define DPRINTF(a)
+#endif
+
+static int semvalid(int semid, struct semid_ds *semaptr);
+
+static struct sem_undo *semu_alloc(struct thread *td);
+static int semundo_adjust(struct thread *td, struct sem_undo **supptr,
+               int semid, int semnum, int adjval);
+static void semundo_clear(int semid, int semnum);
+
+#ifndef _SYS_SYSPROTO_H_
+struct __semctl_args;
+int __semctl(struct thread *td, struct __semctl_args *uap);
+struct semget_args;
+int semget(struct thread *td, struct semget_args *uap);
+struct semop_args;
+int semop(struct thread *td, struct semop_args *uap);
+#endif
+
+#ifndef __CYGWIN__
+/* XXX casting to (sy_call_t *) is bogus, as usual. */
+static sy_call_t *semcalls[] = {
+       (sy_call_t *)__semctl, (sy_call_t *)semget,
+       (sy_call_t *)semop
+};
+#endif
+
+static struct mtx      sem_mtx;        /* semaphore global lock */
+static int     semtots = 0;
+static int     semtot = 0;
+static struct semid_ds *sema;  /* semaphore id pool */
+static struct mtx *sema_mtx;   /* semaphore id pool mutexes*/
+static struct sem *sem;                /* semaphore pool */
+SLIST_HEAD(, sem_undo) semu_list;      /* list of active undo structures */
+static int     *semu;          /* undo structure pool */
+#ifndef __CYGWIN__
+static eventhandler_tag semexit_tag;
+#endif /* __CYGWIN__ */
+
+#define SEMUNDO_MTX            sem_mtx
+#define SEMUNDO_LOCK()         mtx_lock(&SEMUNDO_MTX);
+#define SEMUNDO_HOOKLOCK()     _mtx_lock(&SEMUNDO_MTX, p->winpid, __FILE__, __LINE__);
+#define SEMUNDO_UNLOCK()       mtx_unlock(&SEMUNDO_MTX);
+#define SEMUNDO_LOCKASSERT(how)        mtx_assert(&SEMUNDO_MTX, (how));
+
+struct sem {
+       u_short semval;         /* semaphore value */
+       pid_t   sempid;         /* pid of last operation */
+       u_short semncnt;        /* # awaiting semval > cval */
+       u_short semzcnt;        /* # awaiting semval = 0 */
+};
+
+/*
+ * Undo structure (one per process)
+ */
+struct undo {
+       short   un_adjval;      /* adjust on exit values */
+       short   un_num;         /* semaphore # */
+       int     un_id;          /* semid */
+} un_ent[1];                   /* undo entries */
+
+struct sem_undo {
+       SLIST_ENTRY(sem_undo) un_next;  /* ptr to next active undo structure */
+       struct  proc *un_proc;          /* owner of this structure */
+       short   un_cnt;                 /* # of active entries */
+       struct undo un_ent[1];          /* undo entries */
+};
+
+/*
+ * Configuration parameters
+ */
+#ifndef SEMMNI
+#define SEMMNI 10              /* # of semaphore identifiers */
+#endif
+#ifndef SEMMNS
+#define SEMMNS 60              /* # of semaphores in system */
+#endif
+#ifndef SEMUME
+#define SEMUME 10              /* max # of undo entries per process */
+#endif
+#ifndef SEMMNU
+#define SEMMNU 30              /* # of undo structures in system */
+#endif
+
+/* shouldn't need tuning */
+#ifndef SEMMAP
+#define SEMMAP 30              /* # of entries in semaphore map */
+#endif
+#ifndef SEMMSL
+#define SEMMSL SEMMNS          /* max # of semaphores per id */
+#endif
+#ifndef SEMOPM
+#define SEMOPM 100             /* max # of operations per semop call */
+#endif
+
+#ifndef SEMVMX
+#define SEMVMX 32767           /* semaphore maximum value */
+#endif
+#ifndef SEMAEM
+#define SEMAEM 16384           /* adjust on exit max value */
+#endif
+
+/*
+ * Due to the way semaphore memory is allocated, we have to ensure that
+ * SEMUSZ is properly aligned.
+ */
+
+#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
+
+/* actual size of an undo structure */
+#define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
+
+/*
+ * Macro to find a particular sem_undo vector
+ */
+#define SEMU(ix) \
+       ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
+
+/*
+ * semaphore info struct
+ */
+struct seminfo seminfo = {
+                SEMMNI,         /* # of semaphore identifiers */
+                SEMMNS,         /* # of semaphores in system */
+                SEMMSL,         /* max # of semaphores per id */
+                SEMOPM,         /* max # of operations per semop call */
+                SEMMNU,         /* # of undo structures in system */
+                SEMUME,         /* max # of undo entries per process */
+                SEMVMX,         /* semaphore maximum value */
+                SEMAEM,         /* adjust on exit max value */
+                SEMMAP,         /* # of entries in semaphore map */
+                SEMUSZ          /* size in bytes of undo structure */
+};
+
+#ifndef __CYGWIN__
+SYSCTL_DECL(_kern_ipc);
+SYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, "");
+SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD,
+    NULL, 0, sysctl_sema, "", "");
+#endif /* __CYGWIN__ */
+
+void
+seminit(void)
+{
+       int i;
+
+       TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap);
+       TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni);
+       TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns);
+       TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu);
+       TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl);
+       TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm);
+       TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume);
+       TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz);
+       TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx);
+       TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem);
+
+#ifdef __CYGWIN__
+       /* It's too dangerous a setting to leave it alone. 
+          Keep that clean here. */
+       seminfo.semusz = SEM_ALIGN(offsetof(struct sem_undo,
+                                           un_ent[seminfo.semume]));
+#endif /* __CYGWIN__ */
+
+       sem = (struct sem *) sys_malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK);
+       sema = (struct semid_ds *) sys_malloc(sizeof(struct semid_ds) * seminfo.semmni, M_SEM,
+           M_WAITOK);
+       sema_mtx = (struct mtx *) sys_malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM,
+           M_WAITOK | M_ZERO);
+       semu = (int *) sys_malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK);
+
+       for (i = 0; i < seminfo.semmni; i++) {
+               sema[i].sem_base = 0;
+               sema[i].sem_perm.mode = 0;
+       }
+       for (i = 0; i < seminfo.semmni; i++)
+               mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF);
+       for (i = 0; i < seminfo.semmnu; i++) {
+               struct sem_undo *suptr = SEMU(i);
+               suptr->un_proc = NULL;
+       }
+       SLIST_INIT(&semu_list);
+       mtx_init(&sem_mtx, "sem", NULL, MTX_DEF);
+#ifndef __CYGWIN__
+       semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL,
+           EVENTHANDLER_PRI_ANY);
+#endif /* __CYGWIN__ */
+}
+
+int
+semunload(void)
+{
+#ifndef __CYGWIN__     /* Would result in being unable to shutdown the
+                          server gracefully. */
+       if (semtot != 0)
+               return (EBUSY);
+
+       EVENTHANDLER_DEREGISTER(process_exit, semexit_tag);
+#endif /* __CYGWIN__ */
+       sys_free(sem, M_SEM);
+       sys_free(sema, M_SEM);
+       sys_free(semu, M_SEM);
+       for (int i = 0; i < seminfo.semmni; i++)
+               mtx_destroy(&sema_mtx[i]);
+       mtx_destroy(&sem_mtx);
+       return (0);
+}
+
+#ifndef __CYGWIN__
+static int
+sysvsem_modload(struct module *module, int cmd, void *arg)
+{
+       int error = 0;
+
+       switch (cmd) {
+       case MOD_LOAD:
+               seminit();
+               break;
+       case MOD_UNLOAD:
+               error = semunload();
+               break;
+       case MOD_SHUTDOWN:
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+       return (error);
+}
+
+static moduledata_t sysvsem_mod = {
+       "sysvsem",
+       &sysvsem_modload,
+       NULL
+};
+
+SYSCALL_MODULE_HELPER(semsys);
+SYSCALL_MODULE_HELPER(__semctl);
+SYSCALL_MODULE_HELPER(semget);
+SYSCALL_MODULE_HELPER(semop);
+
+DECLARE_MODULE(sysvsem, sysvsem_mod,
+       SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
+MODULE_VERSION(sysvsem, 1);
+
+/*
+ * Entry point for all SEM calls
+ *
+ * MPSAFE
+ */
+int
+semsys(td, uap)
+       struct thread *td;
+       /* XXX actually varargs. */
+       struct semsys_args /* {
+               int     which;
+               int     a2;
+               int     a3;
+               int     a4;
+               int     a5;
+       } */ *uap;
+{
+       int error;
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+       if (uap->which < 0 ||
+           uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
+               return (EINVAL);
+       error = (*semcalls[uap->which])(td, &uap->a2);
+       return (error);
+}
+#endif /* __CYGWIN__ */
+
+/*
+ * Allocate a new sem_undo structure for a process
+ * (returns ptr to structure or NULL if no more room)
+ */
+
+static struct sem_undo *
+semu_alloc(struct thread *td)
+{
+       int i;
+       struct sem_undo *suptr;
+       struct sem_undo **supptr;
+       int attempt;
+
+       SEMUNDO_LOCKASSERT(MA_OWNED);
+       /*
+        * Try twice to allocate something.
+        * (we'll purge an empty structure after the first pass so
+        * two passes are always enough)
+        */
+
+       for (attempt = 0; attempt < 2; attempt++) {
+               /*
+                * Look for a free structure.
+                * Fill it in and return it if we find one.
+                */
+
+               for (i = 0; i < seminfo.semmnu; i++) {
+                       suptr = SEMU(i);
+                       if (suptr->un_proc == NULL) {
+                               SLIST_INSERT_HEAD(&semu_list, suptr, un_next);
+                               suptr->un_cnt = 0;
+                               suptr->un_proc = td->td_proc;
+                               return(suptr);
+                       }
+               }
+
+               /*
+                * We didn't find a free one, if this is the first attempt
+                * then try to free a structure.
+                */
+
+               if (attempt == 0) {
+                       /* All the structures are in use - try to free one */
+                       int did_something = 0;
+
+                       SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list,
+                           un_next) {
+                               if (suptr->un_cnt == 0) {
+                                       suptr->un_proc = NULL;
+                                       did_something = 1;
+                                       *supptr = SLIST_NEXT(suptr, un_next);
+                                       break;
+                               }
+                       }
+
+                       /* If we didn't free anything then just give-up */
+                       if (!did_something)
+                               return(NULL);
+               } else {
+                       /*
+                        * The second pass failed even though we freed
+                        * something after the first pass!
+                        * This is IMPOSSIBLE!
+                        */
+                       panic("semu_alloc - second attempt failed");
+               }
+       }
+       return (NULL);
+}
+
+/*
+ * Adjust a particular entry for a particular proc
+ */
+
+static int
+semundo_adjust(struct thread *td, struct sem_undo **supptr, int semid,
+              int semnum, int adjval)
+{
+       struct proc *p = td->td_proc;
+       struct sem_undo *suptr;
+       struct undo *sunptr;
+       int i;
+
+       SEMUNDO_LOCKASSERT(MA_OWNED);
+       /* Look for and remember the sem_undo if the caller doesn't provide
+          it */
+
+       suptr = *supptr;
+       if (suptr == NULL) {
+               SLIST_FOREACH(suptr, &semu_list, un_next) {
+                       if (suptr->un_proc == p) {
+                               *supptr = suptr;
+                               break;
+                       }
+               }
+               if (suptr == NULL) {
+                       if (adjval == 0)
+                               return(0);
+                       suptr = semu_alloc(td);
+                       if (suptr == NULL)
+                               return(ENOSPC);
+                       *supptr = suptr;
+               }
+       }
+
+       /*
+        * Look for the requested entry and adjust it (delete if adjval becomes
+        * 0).
+        */
+       sunptr = &suptr->un_ent[0];
+       for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
+               if (sunptr->un_id != semid || sunptr->un_num != semnum)
+                       continue;
+               if (adjval != 0) {
+                       adjval += sunptr->un_adjval;
+                       if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
+                               return (ERANGE);
+               }
+               sunptr->un_adjval = adjval;
+               if (sunptr->un_adjval == 0) {
+                       suptr->un_cnt--;
+                       if (i < suptr->un_cnt)
+                               suptr->un_ent[i] =
+                                   suptr->un_ent[suptr->un_cnt];
+               }
+               return(0);
+       }
+
+       /* Didn't find the right entry - create it */
+       if (adjval == 0)
+               return(0);
+       if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
+               return (ERANGE);
+       if (suptr->un_cnt != seminfo.semume) {
+               sunptr = &suptr->un_ent[suptr->un_cnt];
+               suptr->un_cnt++;
+               sunptr->un_adjval = adjval;
+               sunptr->un_id = semid; sunptr->un_num = semnum;
+       } else
+               return(EINVAL);
+       return(0);
+}
+
+static void
+semundo_clear(int semid, int semnum)
+{
+       struct sem_undo *suptr;
+
+       SEMUNDO_LOCKASSERT(MA_OWNED);
+       SLIST_FOREACH(suptr, &semu_list, un_next) {
+               struct undo *sunptr = &suptr->un_ent[0];
+               int i = 0;
+
+               while (i < suptr->un_cnt) {
+                       if (sunptr->un_id == semid) {
+                               if (semnum == -1 || sunptr->un_num == semnum) {
+                                       suptr->un_cnt--;
+                                       if (i < suptr->un_cnt) {
+                                               suptr->un_ent[i] =
+                                                 suptr->un_ent[suptr->un_cnt];
+                                               continue;
+                                       }
+                               }
+                               if (semnum != -1)
+                                       break;
+                       }
+                       i++, sunptr++;
+               }
+       }
+}
+
+static int
+semvalid(int semid, struct semid_ds *semaptr)
+{
+
+       return ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
+           semaptr->sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0);
+}
+
+/*
+ * Note that the user-mode half of this passes a union, not a pointer
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct __semctl_args {
+       int     semid;
+       int     semnum;
+       int     cmd;
+       union   semun *arg;
+};
+#endif
+
+/*
+ * MPSAFE
+ */
+int
+__semctl(struct thread *td, struct __semctl_args *uap)
+{
+       int semid = uap->semid;
+       int semnum = uap->semnum;
+       int cmd = uap->cmd;
+       u_short *array;
+       union semun *arg = uap->arg;
+       union semun real_arg;
+#ifndef __CYGWIN__
+       struct ucred *cred = td->td_ucred;
+#endif
+       int i, rval, error;
+       struct semid_ds sbuf;
+       struct semid_ds *semaptr;
+       struct mtx *sema_mtxp;
+       u_short usval, count;
+
+       DPRINTF(("call to semctl(%d, %d, %d, 0x%x)\n",
+           semid, semnum, cmd, arg));
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+
+       array = NULL;
+
+       switch(cmd) {
+#ifdef __CYGWIN__
+       case IPC_INFO:
+               if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
+                       return (error);
+               if (!semid) {
+                       error = copyout(&seminfo, real_arg.buf,
+                                       sizeof(struct seminfo));
+                       td->td_retval[0] = error ? -1 : 0;
+                       return (error);
+               }
+               if (semid > seminfo.semmni)
+                       semid = seminfo.semmni;
+               error = copyout(sema, real_arg.buf,
+                               semid * sizeof(struct semid_ds));
+               td->td_retval[0] = error ? -1 : 0;
+               return (error);
+       case SEM_INFO:
+               if (!(error = copyin(arg, &real_arg, sizeof(real_arg)))) {
+                       struct sem_info sem_info;
+                       sem_info.sem_ids = semtots;
+                       sem_info.sem_num = semtot;
+                       error = copyout(&sem_info, real_arg.buf,
+                                       sizeof(struct sem_info));
+               }
+               td->td_retval[0] = error ? -1 : 0;
+               return (error);
+
+#endif /* __CYGWIN__ */
+       case SEM_STAT:
+               if (semid < 0 || semid >= seminfo.semmni)
+                       return (EINVAL);
+               if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
+                       return (error);
+               semaptr = &sema[semid];
+               sema_mtxp = &sema_mtx[semid];
+               mtx_lock(sema_mtxp);
+               if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) {
+                       error = EINVAL;
+                       goto done2;
+               }
+               if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
+                       goto done2;
+               mtx_unlock(sema_mtxp);
+               error = copyout(semaptr, real_arg.buf, sizeof(struct semid_ds));
+               rval = IXSEQ_TO_IPCID(semid,semaptr->sem_perm);
+               if (error == 0)
+                       td->td_retval[0] = rval;
+               return (error);
+       }
+
+       semid = IPCID_TO_IX(semid);
+       if (semid < 0 || semid >= seminfo.semmni)
+               return (EINVAL);
+
+       semaptr = &sema[semid];
+       sema_mtxp = &sema_mtx[semid];
+               
+       error = 0;
+       rval = 0;
+
+       switch (cmd) {
+       case IPC_RMID:
+               mtx_lock(sema_mtxp);
+               if ((error = semvalid(uap->semid, semaptr)) != 0)
+                       goto done2;
+               if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M)))
+                       goto done2;
+#ifdef __CYGWIN__
+               semaptr->sem_perm.cuid = td->ipcblk->uid;
+               semaptr->sem_perm.uid = td->ipcblk->uid;
+#else
+               semaptr->sem_perm.cuid = cred->cr_uid;
+               semaptr->sem_perm.uid = cred->cr_uid;
+#endif
+               semtot -= semaptr->sem_nsems;
+               semtots--;
+               for (i = semaptr->sem_base - sem; i < semtot; i++)
+                       sem[i] = sem[i + semaptr->sem_nsems];
+               for (i = 0; i < seminfo.semmni; i++) {
+                       if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
+                           sema[i].sem_base > semaptr->sem_base)
+                               sema[i].sem_base -= semaptr->sem_nsems;
+               }
+               semaptr->sem_perm.mode = 0;
+               SEMUNDO_LOCK();
+               semundo_clear(semid, -1);
+               SEMUNDO_UNLOCK();
+               wakeup(semaptr);
+               break;
+
+       case IPC_SET:
+               if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
+                       goto done2;
+               if ((error = copyin(real_arg.buf, &sbuf, sizeof(sbuf))) != 0)
+                       goto done2;
+               mtx_lock(sema_mtxp);
+               if ((error = semvalid(uap->semid, semaptr)) != 0)
+                       goto done2;
+               if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M)))
+                       goto done2;
+               semaptr->sem_perm.uid = sbuf.sem_perm.uid;
+               semaptr->sem_perm.gid = sbuf.sem_perm.gid;
+               semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
+                   (sbuf.sem_perm.mode & 0777);
+               semaptr->sem_ctime = time (NULL);
+               break;
+
+       case IPC_STAT:
+               if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
+                       goto done2;
+               mtx_lock(sema_mtxp);
+               if ((error = semvalid(uap->semid, semaptr)) != 0)
+                       goto done2;
+               if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
+                       goto done2;
+               sbuf = *semaptr;
+               mtx_unlock(sema_mtxp);
+               error = copyout(semaptr, real_arg.buf,
+                               sizeof(struct semid_ds));
+               break;
+
+       case GETNCNT:
+               mtx_lock(sema_mtxp);
+               if ((error = semvalid(uap->semid, semaptr)) != 0)
+                       goto done2;
+               if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
+                       goto done2;
+               if (semnum < 0 || semnum >= semaptr->sem_nsems) {
+                       error = EINVAL;
+                       goto done2;
+               }
+               rval = semaptr->sem_base[semnum].semncnt;
+               break;
+
+       case GETPID:
+               mtx_lock(sema_mtxp);
+               if ((error = semvalid(uap->semid, semaptr)) != 0)
+                       goto done2;
+               if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
+                       goto done2;
+               if (semnum < 0 || semnum >= semaptr->sem_nsems) {
+                       error = EINVAL;
+                       goto done2;
+               }
+               rval = semaptr->sem_base[semnum].sempid;
+               break;
+
+       case GETVAL:
+               mtx_lock(sema_mtxp);
+               if ((error = semvalid(uap->semid, semaptr)) != 0)
+                       goto done2;
+               if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
+                       goto done2;
+               if (semnum < 0 || semnum >= semaptr->sem_nsems) {
+                       error = EINVAL;
+                       goto done2;
+               }
+               rval = semaptr->sem_base[semnum].semval;
+               break;
+
+       case GETALL:
+               if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
+                       goto done2;
+               array = (u_short *) sys_malloc(sizeof(*array) * semaptr->sem_nsems, M_TEMP,
+                   M_WAITOK);
+               mtx_lock(sema_mtxp);
+               if ((error = semvalid(uap->semid, semaptr)) != 0)
+                       goto done2;
+               if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
+                       goto done2;
+               for (i = 0; i < semaptr->sem_nsems; i++)
+                       array[i] = semaptr->sem_base[i].semval;
+               mtx_unlock(sema_mtxp);
+               error = copyout(array, real_arg.array,
+                   i * sizeof(real_arg.array[0]));
+               break;
+
+       case GETZCNT:
+               mtx_lock(sema_mtxp);
+               if ((error = semvalid(uap->semid, semaptr)) != 0)
+                       goto done2;
+               if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
+                       goto done2;
+               if (semnum < 0 || semnum >= semaptr->sem_nsems) {
+                       error = EINVAL;
+                       goto done2;
+               }
+               rval = semaptr->sem_base[semnum].semzcnt;
+               break;
+
+       case SETVAL:
+               if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
+                       goto done2;
+               mtx_lock(sema_mtxp);
+               if ((error = semvalid(uap->semid, semaptr)) != 0)
+                       goto done2;
+               if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W)))
+                       goto done2;
+               if (semnum < 0 || semnum >= semaptr->sem_nsems) {
+                       error = EINVAL;
+                       goto done2;
+               }
+               if (real_arg.val < 0 || real_arg.val > seminfo.semvmx) {
+                       error = ERANGE;
+                       goto done2;
+               }
+               semaptr->sem_base[semnum].semval = real_arg.val;
+               SEMUNDO_LOCK();
+               semundo_clear(semid, semnum);
+               SEMUNDO_UNLOCK();
+               wakeup(semaptr);
+               break;
+
+       case SETALL:
+               mtx_lock(sema_mtxp);
+raced:
+               if ((error = semvalid(uap->semid, semaptr)) != 0)
+                       goto done2;
+               count = semaptr->sem_nsems;
+               mtx_unlock(sema_mtxp);
+               if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
+                       goto done2;
+               array = (u_short *) sys_malloc(sizeof(*array) * count, M_TEMP, M_WAITOK);
+               copyin(real_arg.array, array, count * sizeof(*array));
+               if (error)
+                       break;
+               mtx_lock(sema_mtxp);
+               if ((error = semvalid(uap->semid, semaptr)) != 0)
+                       goto done2;
+               /* we could have raced? */
+               if (count != semaptr->sem_nsems) {
+                       sys_free(array, M_TEMP);
+                       array = NULL;
+                       goto raced;
+               }
+               if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W)))
+                       goto done2;
+               for (i = 0; i < semaptr->sem_nsems; i++) {
+                       usval = array[i];
+                       if (usval > seminfo.semvmx) {
+                               error = ERANGE;
+                               break;
+                       }
+                       semaptr->sem_base[i].semval = usval;
+               }
+               SEMUNDO_LOCK();
+               semundo_clear(semid, -1);
+               SEMUNDO_UNLOCK();
+               wakeup(semaptr);
+               break;
+
+       default:
+               error = EINVAL;
+               break;
+       }
+
+       if (error == 0)
+               td->td_retval[0] = rval;
+done2:
+       if (mtx_owned(sema_mtxp))
+               mtx_unlock(sema_mtxp);
+       if (array != NULL)
+               sys_free(array, M_TEMP);
+       return(error);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct semget_args {
+       key_t   key;
+       int     nsems;
+       int     semflg;
+};
+#endif
+
+/*
+ * MPSAFE
+ */
+int
+semget(struct thread *td, struct semget_args *uap)
+{
+       int semid, error = 0;
+       key_t key = uap->key;
+       int nsems = uap->nsems;
+       int semflg = uap->semflg;
+#ifndef __CYGWIN__
+       struct ucred *cred = td->td_ucred;
+#endif
+
+       DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+
+       mtx_lock(&Giant);
+       if (key != IPC_PRIVATE) {
+               for (semid = 0; semid < seminfo.semmni; semid++) {
+                       if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
+                           sema[semid].sem_perm.key == key)
+                               break;
+               }
+               if (semid < seminfo.semmni) {
+                       DPRINTF(("found public key\n"));
+                       if ((error = ipcperm(td, &sema[semid].sem_perm,
+                           semflg & 0700))) {
+                               goto done2;
+                       }
+                       if (nsems > 0 && sema[semid].sem_nsems < nsems) {
+                               DPRINTF(("too small\n"));
+                               error = EINVAL;
+                               goto done2;
+                       }
+                       if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
+                               DPRINTF(("not exclusive\n"));
+                               error = EEXIST;
+                               goto done2;
+                       }
+                       goto found;
+               }
+       }
+
+       DPRINTF(("need to allocate the semid_ds\n"));
+       if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
+               if (nsems <= 0 || nsems > seminfo.semmsl) {
+                       DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
+                           seminfo.semmsl));
+                       error = EINVAL;
+                       goto done2;
+               }
+               if (nsems > seminfo.semmns - semtot) {
+                       DPRINTF((
+                           "not enough semaphores left (need %d, got %d)\n",
+                           nsems, seminfo.semmns - semtot));
+                       error = ENOSPC;
+                       goto done2;
+               }
+               for (semid = 0; semid < seminfo.semmni; semid++) {
+                       if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
+                               break;
+               }
+               if (semid == seminfo.semmni) {
+                       DPRINTF(("no more semid_ds's available\n"));
+                       error = ENOSPC;
+                       goto done2;
+               }
+               DPRINTF(("semid %d is available\n", semid));
+               sema[semid].sem_perm.key = key;
+#ifdef __CYGWIN__
+               sema[semid].sem_perm.cuid = td->ipcblk->uid;
+               sema[semid].sem_perm.uid = td->ipcblk->uid;
+               sema[semid].sem_perm.cgid = td->ipcblk->gid;
+               sema[semid].sem_perm.gid = td->ipcblk->gid;
+#else
+               sema[semid].sem_perm.cuid = cred->cr_uid;
+               sema[semid].sem_perm.uid = cred->cr_uid;
+               sema[semid].sem_perm.cgid = cred->cr_gid;
+               sema[semid].sem_perm.gid = cred->cr_gid;
+#endif
+               sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
+               sema[semid].sem_perm.seq =
+                   (sema[semid].sem_perm.seq + 1) & 0x7fff;
+               sema[semid].sem_nsems = nsems;
+               sema[semid].sem_otime = 0;
+               sema[semid].sem_ctime = time (NULL);
+               sema[semid].sem_base = &sem[semtot];
+               semtot += nsems;
+               semtots++;
+               bzero(sema[semid].sem_base,
+                   sizeof(sema[semid].sem_base[0])*nsems);
+               DPRINTF(("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
+                   &sem[semtot]));
+       } else {
+               DPRINTF(("didn't find it and wasn't asked to create it\n"));
+               error = ENOENT;
+               goto done2;
+       }
+
+found:
+       td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
+done2:
+#ifdef __CYGWIN__
+       if (!error)
+               ipcexit_creat_hookthread (td);
+#endif
+       mtx_unlock(&Giant);
+       return (error);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct semop_args {
+       int     semid;
+       struct  sembuf *sops;
+       size_t  nsops;
+};
+#endif
+
+/*
+ * MPSAFE
+ */
+int
+semop(struct thread *td, struct semop_args *uap)
+{
+       int semid = uap->semid;
+       size_t nsops = uap->nsops;
+       struct sembuf *sops;
+       struct semid_ds *semaptr;
+       struct sembuf *sopptr = 0;
+       struct sem *semptr = 0;
+       struct sem_undo *suptr;
+       struct mtx *sema_mtxp;
+       size_t i, j, k;
+       int error;
+       int do_wakeup, do_undos;
+
+       DPRINTF(("call to semop(%d, 0x%x, %u)\n", semid, uap->sops, nsops));
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+
+       semid = IPCID_TO_IX(semid);     /* Convert back to zero origin */
+
+       if (semid < 0 || semid >= seminfo.semmni)
+               return (EINVAL);
+
+       /* Allocate memory for sem_ops */
+       if (nsops > (unsigned long) seminfo.semopm) {
+               DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm,
+                   nsops));
+               return (E2BIG);
+       }
+       sops = (struct sembuf *) sys_malloc(nsops * sizeof(sops[0]), M_SEM, M_WAITOK);
+       if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) {
+               DPRINTF(("error = %d from copyin(%08x, %08x, %d)\n", error,
+                   uap->sops, sops, nsops * sizeof(sops[0])));
+               sys_free(sops, M_SEM);
+               return (error);
+       }
+
+       semaptr = &sema[semid];
+       sema_mtxp = &sema_mtx[semid];
+       mtx_lock(sema_mtxp);
+       if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) {
+               error = EINVAL;
+               goto done2;
+       }
+       if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
+               error = EINVAL;
+               goto done2;
+       }
+       /*
+        * Initial pass thru sops to see what permissions are needed.
+        * Also perform any checks that don't need repeating on each
+        * attempt to satisfy the request vector.
+        */
+       j = 0;          /* permission needed */
+       do_undos = 0;
+       for (i = 0; i < nsops; i++) {
+               sopptr = &sops[i];
+               if (sopptr->sem_num >= semaptr->sem_nsems) {
+                       error = EFBIG;
+                       goto done2;
+               }
+               if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0)
+                       do_undos = 1;
+               j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A;
+       }
+
+       if ((error = ipcperm(td, &semaptr->sem_perm, j))) {
+               DPRINTF(("error = %d from ipaccess\n", error));
+               goto done2;
+       }
+
+       /*
+        * Loop trying to satisfy the vector of requests.
+        * If we reach a point where we must wait, any requests already
+        * performed are rolled back and we go to sleep until some other
+        * process wakes us up.  At this point, we start all over again.
+        *
+        * This ensures that from the perspective of other tasks, a set
+        * of requests is atomic (never partially satisfied).
+        */
+       for (;;) {
+               do_wakeup = 0;
+               error = 0;      /* error return if necessary */
+
+               for (i = 0; i < nsops; i++) {
+                       sopptr = &sops[i];
+                       semptr = &semaptr->sem_base[sopptr->sem_num];
+
+                       DPRINTF((
+                           "semop:  semaptr=%x, sem_base=%x, "
+                           "semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
+                           semaptr, semaptr->sem_base, semptr,
+                           sopptr->sem_num, semptr->semval, sopptr->sem_op,
+                           (sopptr->sem_flg & IPC_NOWAIT) ?
+                           "nowait" : "wait"));
+
+                       if (sopptr->sem_op < 0) {
+                               if (semptr->semval + sopptr->sem_op < 0) {
+                                       DPRINTF(("semop:  can't do it now\n"));
+                                       break;
+                               } else {
+                                       semptr->semval += sopptr->sem_op;
+                                       if (semptr->semval == 0 &&
+                                           semptr->semzcnt > 0)
+                                               do_wakeup = 1;
+                               }
+                       } else if (sopptr->sem_op == 0) {
+                               if (semptr->semval != 0) {
+                                       DPRINTF(("semop:  not zero now\n"));
+                                       break;
+                               }
+                       } else if (semptr->semval + sopptr->sem_op >
+                           seminfo.semvmx) {
+                               error = ERANGE;
+                               break;
+                       } else {
+                               if (semptr->semncnt > 0)
+                                       do_wakeup = 1;
+                               semptr->semval += sopptr->sem_op;
+                       }
+               }
+
+               /*
+                * Did we get through the entire vector?
+                */
+               if (i >= nsops)
+                       goto done;
+
+               /*
+                * No ... rollback anything that we've already done
+                */
+               DPRINTF(("semop:  rollback 0 through %d\n", i-1));
+               for (j = 0; j < i; j++)
+                       semaptr->sem_base[sops[j].sem_num].semval -=
+                           sops[j].sem_op;
+
+               /* If we detected an error, return it */
+               if (error != 0)
+                       goto done2;
+
+               /*
+                * If the request that we couldn't satisfy has the
+                * NOWAIT flag set then return with EAGAIN.
+                */
+               if (sopptr->sem_flg & IPC_NOWAIT) {
+                       error = EAGAIN;
+                       goto done2;
+               }
+
+               if (sopptr->sem_op == 0)
+                       semptr->semzcnt++;
+               else
+                       semptr->semncnt++;
+
+               DPRINTF(("semop:  good night!\n"));
+               error = msleep(semaptr, sema_mtxp, (PZERO - 4) | PCATCH,
+                   "semwait", 0);
+               DPRINTF(("semop:  good morning (error=%d)!\n", error));
+
+               if (error != 0) {
+#ifdef __CYGWIN__
+                   if (error != EIDRM)
+#endif /* __CYGWIN__ */
+                       error = EINTR;
+                       goto done2;
+               }
+               DPRINTF(("semop:  good morning!\n"));
+
+               /*
+                * Make sure that the semaphore still exists
+                */
+               if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
+                   semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
+                       error = EIDRM;
+                       goto done2;
+               }
+
+               /*
+                * The semaphore is still alive.  Readjust the count of
+                * waiting processes.
+                */
+               if (sopptr->sem_op == 0)
+                       semptr->semzcnt--;
+               else
+                       semptr->semncnt--;
+       }
+
+done:
+       /*
+        * Process any SEM_UNDO requests.
+        */
+       if (do_undos) {
+               SEMUNDO_LOCK();
+               suptr = NULL;
+               for (i = 0; i < nsops; i++) {
+                       /*
+                        * We only need to deal with SEM_UNDO's for non-zero
+                        * op's.
+                        */
+                       int adjval;
+
+                       if ((sops[i].sem_flg & SEM_UNDO) == 0)
+                               continue;
+                       adjval = sops[i].sem_op;
+                       if (adjval == 0)
+                               continue;
+                       error = semundo_adjust(td, &suptr, semid,
+                           sops[i].sem_num, -adjval);
+                       if (error == 0)
+                               continue;
+
+                       /*
+                        * Oh-Oh!  We ran out of either sem_undo's or undo's.
+                        * Rollback the adjustments to this point and then
+                        * rollback the semaphore ups and down so we can return
+                        * with an error with all structures restored.  We
+                        * rollback the undo's in the exact reverse order that
+                        * we applied them.  This guarantees that we won't run
+                        * out of space as we roll things back out.
+                        */
+                       for (j = 0; j < i; j++) {
+                               k = i - j - 1;
+                               if ((sops[k].sem_flg & SEM_UNDO) == 0)
+                                       continue;
+                               adjval = sops[k].sem_op;
+                               if (adjval == 0)
+                                       continue;
+                               if (semundo_adjust(td, &suptr, semid,
+                                   sops[k].sem_num, adjval) != 0)
+                                       panic("semop - can't undo undos");
+                       }
+
+                       for (j = 0; j < nsops; j++)
+                               semaptr->sem_base[sops[j].sem_num].semval -=
+                                   sops[j].sem_op;
+
+                       DPRINTF(("error = %d from semundo_adjust\n", error));
+                       SEMUNDO_UNLOCK();
+                       goto done2;
+               } /* loop through the sops */
+               SEMUNDO_UNLOCK();
+       } /* if (do_undos) */
+
+       /* We're definitely done - set the sempid's and time */
+       for (i = 0; i < nsops; i++) {
+               sopptr = &sops[i];
+               semptr = &semaptr->sem_base[sopptr->sem_num];
+               semptr->sempid = td->td_proc->p_pid;
+       }
+       semaptr->sem_otime = time (NULL);
+
+       /*
+        * Do a wakeup if any semaphore was up'd whilst something was
+        * sleeping on it.
+        */
+       if (do_wakeup) {
+               DPRINTF(("semop:  doing wakeup\n"));
+               wakeup(semaptr);
+               DPRINTF(("semop:  back from wakeup\n"));
+       }
+       DPRINTF(("semop:  done\n"));
+       td->td_retval[0] = 0;
+done2:
+       mtx_unlock(sema_mtxp);
+       sys_free(sops, M_SEM);
+       return (error);
+}
+
+/*
+ * Go through the undo structures for this process and apply the adjustments to
+ * semaphores.
+ */
+void
+semexit_myhook(void *arg, struct proc *p)
+{
+       struct sem_undo *suptr;
+       struct sem_undo **supptr;
+
+#ifdef __CYGWIN__
+       /*
+        * Search all mutexes, if some of them are still owned by the
+        * leaving process.  If so, unlock them.
+        */
+       if (sem_mtx.owner == p->winpid)
+               mtx_unlock(&sem_mtx);
+       for (int i = 0; i < seminfo.semmni; i++)
+               if (sema_mtx[i].owner == p->winpid)
+                       mtx_unlock(&sema_mtx[i]);
+#endif /* __CYGWIN__ */
+
+       /*
+        * Go through the chain of undo vectors looking for one
+        * associated with this process.
+        */
+       SEMUNDO_HOOKLOCK();
+       SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, un_next) {
+               if (suptr->un_proc == p)
+                       break;
+       }
+       SEMUNDO_UNLOCK();
+
+       if (suptr == NULL)
+               return;
+
+       DPRINTF(("proc @%08x has undo structure with %d entries\n", p,
+           suptr->un_cnt));
+
+       /*
+        * If there are any active undo elements then process them.
+        */
+       if (suptr->un_cnt > 0) {
+               int ix;
+
+               for (ix = 0; ix < suptr->un_cnt; ix++) {
+                       int semid = suptr->un_ent[ix].un_id;
+                       int semnum = suptr->un_ent[ix].un_num;
+                       int adjval = suptr->un_ent[ix].un_adjval;
+                       struct semid_ds *semaptr;
+                       struct mtx *sema_mtxp;
+
+                       semaptr = &sema[semid];
+                       sema_mtxp = &sema_mtx[semid];
+#ifdef __CYGWIN__
+                       _mtx_lock(sema_mtxp, p->winpid, __FILE__, __LINE__);
+#else
+                       mtx_lock(sema_mtxp);
+#endif
+                       SEMUNDO_HOOKLOCK();
+                       if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
+                               panic("semexit - semid not allocated");
+                       if (semnum >= semaptr->sem_nsems)
+                               panic("semexit - semnum out of range");
+
+                       DPRINTF((
+                           "semexit:  %08x id=%d num=%d(adj=%d) ; sem=%d\n",
+                           suptr->un_proc, suptr->un_ent[ix].un_id,
+                           suptr->un_ent[ix].un_num,
+                           suptr->un_ent[ix].un_adjval,
+                           semaptr->sem_base[semnum].semval));
+
+                       if (adjval < 0) {
+                               if (semaptr->sem_base[semnum].semval < -adjval)
+                                       semaptr->sem_base[semnum].semval = 0;
+                               else
+                                       semaptr->sem_base[semnum].semval +=
+                                           adjval;
+                       } else
+                               semaptr->sem_base[semnum].semval += adjval;
+
+                       wakeup(semaptr);
+                       DPRINTF(("semexit:  back from wakeup\n"));
+                       mtx_unlock(sema_mtxp);
+                       SEMUNDO_UNLOCK();
+               }
+       }
+
+       /*
+        * Deallocate the undo vector.
+        */
+       DPRINTF(("removing vector\n"));
+       suptr->un_proc = NULL;
+       *supptr = SLIST_NEXT(suptr, un_next);
+}
+
+#ifndef __CYGWIN__
+static int
+sysctl_sema(SYSCTL_HANDLER_ARGS)
+{
+
+       return (SYSCTL_OUT(req, sema,
+           sizeof(struct semid_ds) * seminfo.semmni));
+}
+#endif /* __CYGWIN__ */
+#endif /* __OUTSIDE_CYGWIN__ */
diff --git a/winsup/cygserver/sysv_shm.cc b/winsup/cygserver/sysv_shm.cc
new file mode 100644 (file)
index 0000000..70ed1a3
--- /dev/null
@@ -0,0 +1,1025 @@
+/*     $NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $      */
+/*
+ * Copyright (c) 1994 Adam Glass and Charles Hannum.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by Adam Glass and Charles
+ *     Hannum.
+ * 4. The names of the authors may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This file is heavily changed to become part of Cygwin's cygserver.
+ */
+
+#ifdef __OUTSIDE_CYGWIN__
+#include "woutsup.h"
+#include <sys/cdefs.h>
+#ifndef __FBSDID
+#define __FBSDID(s)    const char version[] = (s)
+#endif
+__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/kern/sysv_shm.c,v 1.89 2003/11/07 04:47:14 rwatson Exp $");
+
+#define _KERNEL 1
+#define __BSD_VISIBLE 1
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/shm.h>
+#include <malloc.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/sysproto.h>
+
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+#include "cygserver.h"
+#include "process.h"
+#include "cygserver_ipc.h"
+
+#ifdef __CYGWIN__
+#ifndef PAGE_SIZE
+#define PAGE_SIZE (getpagesize ())
+#endif
+#ifndef PAGE_MASK
+#define PAGE_MASK (PAGE_SIZE - 1)
+#endif
+#define btoc(b)        (((b) + PAGE_MASK) / PAGE_SIZE)
+#define round_page(p) ((((unsigned long)(p)) + PAGE_MASK) & ~(PAGE_MASK))
+#define ACCESSPERMS (0777)
+#define GIANT_REQUIRED mtx_assert(&Giant, MA_OWNED)
+#define KERN_SUCCESS 0
+#define VM_PROT_READ   PROT_READ
+#define VM_PROT_WRITE  PROT_WRITE
+#define VM_INHERIT_SHARE 0
+#define OBJT_PHYS  0
+#define OBJT_SWAP  0
+#define VM_PROT_DEFAULT 0
+#define VM_OBJECT_LOCK(a)
+#define vm_object_clear_flag(a,b)
+#define vm_object_set_flag(a,b)
+#define VM_OBJECT_UNLOCK(a)
+#define vm_object_reference(a)
+#define vm_map_remove(a,b,c) KERN_SUCCESS
+#define vm_map_find(a,b,c,d,e,f,g,h,i) KERN_SUCCESS
+#define vm_map_inherit(a,b,c,d)
+typedef int vm_prot_t;
+#endif /* __CYGWIN__ */
+
+#ifndef __CYGWIN__
+static MALLOC_DEFINE(M_SHM, "shm", "SVID compatible shared memory segments");
+
+struct oshmctl_args;
+static int oshmctl(struct thread *td, struct oshmctl_args *uap);
+#endif /* __CYGWIN__ */
+
+static int shmget_allocate_segment(struct thread *td,
+    struct shmget_args *uap, int mode);
+static int shmget_existing(struct thread *td, struct shmget_args *uap,
+    int mode, int segnum);
+
+#ifndef __CYGWIN__
+/* XXX casting to (sy_call_t *) is bogus, as usual. */
+static sy_call_t *shmcalls[] = {
+       (sy_call_t *)shmat, (sy_call_t *)oshmctl,
+       (sy_call_t *)shmdt, (sy_call_t *)shmget,
+       (sy_call_t *)shmctl
+};
+#endif /* __CYGWIN__ */
+
+#define        SHMSEG_FREE             0x0200
+#define        SHMSEG_REMOVED          0x0400
+#define        SHMSEG_ALLOCATED        0x0800
+#define        SHMSEG_WANTED           0x1000
+
+static int shm_last_free, shm_nused, shm_committed, shmalloced, shm_nattch;
+static struct shmid_ds *shmsegs;
+
+struct shm_handle {
+       /* vm_offset_t kva; */
+       vm_object_t shm_object;
+};
+
+struct shmmap_state {
+       vm_offset_t va;
+       int shmid;
+};
+
+static void shm_deallocate_segment(struct shmid_ds *);
+static int shm_find_segment_by_key(key_t);
+static struct shmid_ds *shm_find_segment_by_shmid(int);
+static struct shmid_ds *shm_find_segment_by_shmidx(int);
+static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *);
+static void shmrealloc(void);
+
+/*
+ * Tuneable values.
+ */
+#ifndef SHMMAXPGS
+#define        SHMMAXPGS       8192    /* Note: sysv shared memory is swap backed. */
+#endif
+#ifndef SHMMAX
+#define        SHMMAX  (SHMMAXPGS*PAGE_SIZE)
+#endif
+#ifndef SHMMIN
+#define        SHMMIN  1
+#endif
+#ifndef SHMMNI
+#define        SHMMNI  192
+#endif
+#ifndef SHMSEG
+#define        SHMSEG  128
+#endif
+#ifndef SHMALL
+#define        SHMALL  (SHMMAXPGS)
+#endif
+
+struct shminfo shminfo = {
+       SHMMAX,
+       SHMMIN,
+       SHMMNI,
+       SHMSEG,
+       SHMALL
+};
+
+#ifndef __CYGWIN__
+static int shm_use_phys;
+#else
+static long shm_use_phys;
+static long shm_allow_removed;
+#endif /* __CYGWIN__ */
+
+#ifndef __CYGWIN__
+struct shm_info shm_info;
+#endif /* __CYGWIN__ */
+
+#ifndef __CYGWIN__
+SYSCTL_DECL(_kern_ipc);
+SYSCTL_INT(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RW, &shminfo.shmmax, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RW, &shminfo.shmmin, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RDTUN, &shminfo.shmmni, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RDTUN, &shminfo.shmseg, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RW, &shminfo.shmall, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW,
+    &shm_use_phys, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RW,
+    &shm_allow_removed, 0, "");
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLFLAG_RD,
+    NULL, 0, sysctl_shmsegs, "", "");
+#endif /* __CYGWIN__ */
+
+static int
+shm_find_segment_by_key(key_t key)
+{
+       int i;
+
+       for (i = 0; i < shmalloced; i++)
+               if ((shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) &&
+                   shmsegs[i].shm_perm.key == key)
+                       return (i);
+       return (-1);
+}
+
+static struct shmid_ds *
+shm_find_segment_by_shmid(int shmid)
+{
+       int segnum;
+       struct shmid_ds *shmseg;
+
+       segnum = IPCID_TO_IX(shmid);
+       if (segnum < 0 || segnum >= shmalloced)
+               return (NULL);
+       shmseg = &shmsegs[segnum];
+       if ((shmseg->shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
+           (!shm_allow_removed &&
+            (shmseg->shm_perm.mode & SHMSEG_REMOVED) != 0) ||
+           shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid))
+               return (NULL);
+       return (shmseg);
+}
+
+static struct shmid_ds *
+shm_find_segment_by_shmidx(int segnum)
+{
+       struct shmid_ds *shmseg;
+
+       if (segnum < 0 || segnum >= shmalloced)
+               return (NULL);
+       shmseg = &shmsegs[segnum];
+       if ((shmseg->shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
+           (!shm_allow_removed &&
+            (shmseg->shm_perm.mode & SHMSEG_REMOVED) != 0))
+               return (NULL);
+       return (shmseg);
+}
+
+static void
+shm_deallocate_segment(struct shmid_ds *shmseg)
+{
+       struct shm_handle *shm_handle;
+       size_t size;
+
+       GIANT_REQUIRED;
+
+       shm_handle = shmseg->shm_internal;
+       vm_object_deallocate(shm_handle->shm_object);
+       sys_free(shm_handle, M_SHM);
+       shmseg->shm_internal = NULL;
+       size = round_page(shmseg->shm_segsz);
+       shm_committed -= btoc(size);
+       shm_nused--;
+       shmseg->shm_perm.mode = SHMSEG_FREE;
+}
+
+static int
+shm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s)
+{
+       struct shmid_ds *shmseg;
+       int segnum, result;
+       size_t size;
+
+       GIANT_REQUIRED;
+
+       segnum = IPCID_TO_IX(shmmap_s->shmid);
+       shmseg = &shmsegs[segnum];
+       size = round_page(shmseg->shm_segsz);
+       result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size);
+       if (result != KERN_SUCCESS)
+               return (EINVAL);
+       shmmap_s->shmid = -1;
+       shmseg->shm_dtime = time (NULL);
+       --shm_nattch;
+       if ((--shmseg->shm_nattch <= 0) &&
+           (shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
+               shm_deallocate_segment(shmseg);
+               shm_last_free = segnum;
+       }
+       return (0);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct shmdt_args {
+       const void *shmaddr;
+};
+#endif
+
+/*
+ * MPSAFE
+ */
+int
+shmdt(struct thread *td, struct shmdt_args *uap)
+{
+       struct proc *p = td->td_proc;
+       struct shmmap_state *shmmap_s;
+       int i;
+       int error = 0;
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+       mtx_lock(&Giant);
+       shmmap_s = p->p_vmspace->vm_shm;
+       if (shmmap_s == NULL) {
+               error = EINVAL;
+               goto done2;
+       }
+       for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
+               if (shmmap_s->shmid != -1 &&
+                   shmmap_s->va == (vm_offset_t)uap->shmaddr) {
+                       break;
+               }
+       }
+       if (i == shminfo.shmseg) {
+               error = EINVAL;
+               goto done2;
+       }
+       error = shm_delete_mapping(p->p_vmspace, shmmap_s);
+done2:
+       mtx_unlock(&Giant);
+       return (error);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct shmat_args {
+       int shmid;
+       const void *shmaddr;
+       int shmflg;
+};
+#endif
+
+/*
+ * MPSAFE
+ */
+int
+kern_shmat(struct thread *td, int shmid, const void *shmaddr, int shmflg)
+{
+       struct proc *p = td->td_proc;
+       int i, flags;
+       struct shmid_ds *shmseg;
+       struct shmmap_state *shmmap_s = NULL;
+       struct shm_handle *shm_handle;
+       vm_offset_t attach_va;
+       vm_prot_t prot;
+       vm_size_t size;
+       int rv;
+       int error = 0;
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+       mtx_lock(&Giant);
+       shmmap_s = p->p_vmspace->vm_shm;
+       if (shmmap_s == NULL) {
+               size = shminfo.shmseg * sizeof(struct shmmap_state);
+               shmmap_s = (struct shmmap_state *) sys_malloc(size, M_SHM, M_WAITOK);
+               for (i = 0; i < shminfo.shmseg; i++)
+                       shmmap_s[i].shmid = -1;
+               p->p_vmspace->vm_shm = shmmap_s;
+       }
+       shmseg = shm_find_segment_by_shmid(shmid);
+       if (shmseg == NULL) {
+               error = EINVAL;
+               goto done2;
+       }
+       error = ipcperm(td, &shmseg->shm_perm,
+           (shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
+       if (error)
+               goto done2;
+       for (i = 0; i < shminfo.shmseg; i++) {
+               if (shmmap_s->shmid == -1)
+                       break;
+               shmmap_s++;
+       }
+       if (i >= shminfo.shmseg) {
+               error = EMFILE;
+               goto done2;
+       }
+       size = round_page(shmseg->shm_segsz);
+#ifdef VM_PROT_READ_IS_EXEC
+       prot = VM_PROT_READ | VM_PROT_EXECUTE;
+#else
+       prot = VM_PROT_READ;
+#endif
+       if ((shmflg & SHM_RDONLY) == 0)
+               prot |= VM_PROT_WRITE;
+       flags = MAP_ANON | MAP_SHARED;
+       if (shmaddr) {
+               flags |= MAP_FIXED;
+               if (shmflg & SHM_RND) {
+                       attach_va = (vm_offset_t)shmaddr & ~(SHMLBA-1);
+               } else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0) {
+                       attach_va = (vm_offset_t)shmaddr;
+               } else {
+                       error = EINVAL;
+                       goto done2;
+               }
+       } else {
+               /*
+                * This is just a hint to vm_map_find() about where to
+                * put it.
+                */
+#ifdef __CYGWIN__
+               attach_va = 0;
+#else
+               attach_va = round_page((vm_offset_t)p->p_vmspace->vm_taddr
+                   + maxtsiz + maxdsiz);
+#endif
+       }
+
+       shm_handle = shmseg->shm_internal;
+       vm_object_reference(shm_handle->shm_object);
+       rv = vm_map_find(&p->p_vmspace->vm_map, shm_handle->shm_object,
+               0, &attach_va, size, (flags & MAP_FIXED)?0:1, prot, prot, 0);
+       if (rv != KERN_SUCCESS) {
+               error = ENOMEM;
+               goto done2;
+       }
+       vm_map_inherit(&p->p_vmspace->vm_map,
+               attach_va, attach_va + size, VM_INHERIT_SHARE);
+
+       shmmap_s->va = attach_va;
+       shmmap_s->shmid = shmid;
+       shmseg->shm_lpid = p->p_pid;
+       shmseg->shm_atime = time (NULL);
+       shmseg->shm_nattch++;
+       shm_nattch++;
+       td->td_retval[0] = attach_va;
+done2:
+       mtx_unlock(&Giant);
+       return (error);
+}
+
+int
+shmat(struct thread *td, struct shmat_args *uap)
+{
+       return kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg);
+}
+
+#ifndef __CYGWIN__
+struct oshmid_ds {
+       struct  ipc_perm shm_perm;      /* operation perms */
+       int     shm_segsz;              /* size of segment (bytes) */
+       u_short shm_cpid;               /* pid, creator */
+       u_short shm_lpid;               /* pid, last operation */
+       short   shm_nattch;             /* no. of current attaches */
+       time_t  shm_atime;              /* last attach time */
+       time_t  shm_dtime;              /* last detach time */
+       time_t  shm_ctime;              /* last change time */
+       void    *shm_handle;            /* internal handle for shm segment */
+};
+
+struct oshmctl_args {
+       int shmid;
+       int cmd;
+       struct oshmid_ds *ubuf;
+};
+
+/*
+ * MPSAFE
+ */
+static int
+oshmctl(struct thread *td, struct oshmctl_args *uap)
+{
+#ifdef COMPAT_43
+       int error = 0;
+       struct shmid_ds *shmseg;
+       struct oshmid_ds outbuf;
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+       mtx_lock(&Giant);
+       shmseg = shm_find_segment_by_shmid(uap->shmid);
+       if (shmseg == NULL) {
+               error = EINVAL;
+               goto done2;
+       }
+       switch (uap->cmd) {
+       case IPC_STAT:
+               error = ipcperm(td, &shmseg->shm_perm, IPC_R);
+               if (error)
+                       goto done2;
+               outbuf.shm_perm = shmseg->shm_perm;
+               outbuf.shm_segsz = shmseg->shm_segsz;
+               outbuf.shm_cpid = shmseg->shm_cpid;
+               outbuf.shm_lpid = shmseg->shm_lpid;
+               outbuf.shm_nattch = shmseg->shm_nattch;
+               outbuf.shm_atime = shmseg->shm_atime;
+               outbuf.shm_dtime = shmseg->shm_dtime;
+               outbuf.shm_ctime = shmseg->shm_ctime;
+               outbuf.shm_handle = shmseg->shm_internal;
+               error = copyout(&outbuf, uap->ubuf, sizeof(outbuf));
+               if (error)
+                       goto done2;
+               break;
+       default:
+               /* XXX casting to (sy_call_t *) is bogus, as usual. */
+               error = ((sy_call_t *)shmctl)(td, uap);
+               break;
+       }
+done2:
+       mtx_unlock(&Giant);
+       return (error);
+#else
+       return (EINVAL);
+#endif
+}
+#endif /* __CYGWIN__ */
+
+#ifndef _SYS_SYSPROTO_H_
+struct shmctl_args {
+       int shmid;
+       int cmd;
+       struct shmid_ds *buf;
+};
+#endif
+
+/*
+ * MPSAFE
+ */
+int
+kern_shmctl(struct thread *td, int shmid, int cmd, void *buf, size_t *bufsz)
+{
+       int error = 0;
+       struct shmid_ds *shmseg;
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+
+       mtx_lock(&Giant);
+       switch (cmd) {
+       case IPC_INFO:
+               memcpy(buf, &shminfo, sizeof(shminfo));
+               if (bufsz)
+                       *bufsz = sizeof(shminfo);
+               td->td_retval[0] = shmalloced;
+               goto done2;
+       case SHM_INFO: {
+               struct shm_info shm_info;
+               shm_info.used_ids = shm_nused;
+               shm_info.shm_tot = shm_committed * PAGE_SIZE;
+#ifdef __CYGWIN__
+               shm_info.shm_atts = shm_nattch;
+#else
+               shm_info.shm_rss = 0;   /*XXX where to get from ? */
+               shm_info.shm_swp = 0;   /*XXX where to get from ? */
+               shm_info.swap_attempts = 0;     /*XXX where to get from ? */
+               shm_info.swap_successes = 0;    /*XXX where to get from ? */
+#endif /* __CYGWIN__ */
+               memcpy(buf, &shm_info, sizeof(shm_info));
+               if (bufsz)
+                       *bufsz = sizeof(shm_info);
+               td->td_retval[0] = shmalloced;
+               goto done2;
+       }
+       }
+       if (cmd == SHM_STAT)
+               shmseg = shm_find_segment_by_shmidx(shmid);
+       else
+               shmseg = shm_find_segment_by_shmid(shmid);
+       if (shmseg == NULL) {
+               error = EINVAL;
+               goto done2;
+       }
+       switch (cmd) {
+       case SHM_STAT:
+       case IPC_STAT:
+               error = ipcperm(td, &shmseg->shm_perm, IPC_R);
+               if (error)
+                       goto done2;
+               memcpy(buf, shmseg, sizeof(struct shmid_ds));
+               if (bufsz)
+                       *bufsz = sizeof(struct shmid_ds);
+               if (cmd == SHM_STAT)
+                       td->td_retval[0] = IXSEQ_TO_IPCID(shmid, shmseg->shm_perm);
+               break;
+       case IPC_SET: {
+               struct shmid_ds *shmid;
+
+               shmid = (struct shmid_ds *)buf;
+               error = ipcperm(td, &shmseg->shm_perm, IPC_M);
+               if (error)
+                       goto done2;
+               shmseg->shm_perm.uid = shmid->shm_perm.uid;
+               shmseg->shm_perm.gid = shmid->shm_perm.gid;
+               shmseg->shm_perm.mode =
+                   (shmseg->shm_perm.mode & ~ACCESSPERMS) |
+                   (shmid->shm_perm.mode & ACCESSPERMS);
+               shmseg->shm_ctime = time (NULL);
+               break;
+       }
+       case IPC_RMID:
+               error = ipcperm(td, &shmseg->shm_perm, IPC_M);
+               if (error)
+                       goto done2;
+               shmseg->shm_perm.key = IPC_PRIVATE;
+               shmseg->shm_perm.mode |= SHMSEG_REMOVED;
+               if (shmseg->shm_nattch <= 0) {
+                       shm_deallocate_segment(shmseg);
+                       shm_last_free = IPCID_TO_IX(shmid);
+               }
+               break;
+#if 0
+       case SHM_LOCK:
+       case SHM_UNLOCK:
+#endif
+       default:
+               error = EINVAL;
+               break;
+       }
+done2:
+       mtx_unlock(&Giant);
+       return (error);
+}
+
+int
+shmctl(struct thread *td, struct shmctl_args *uap)
+{
+       int error = 0;
+       struct shmid_ds buf;
+       size_t bufsz;
+       
+       /* IPC_SET needs to copyin the buffer before calling kern_shmctl */
+       if (uap->cmd == IPC_SET) {
+               if ((error = copyin(uap->buf, &buf, sizeof(struct shmid_ds))))
+                       goto done;
+       }
+#ifdef __CYGWIN__
+       if (uap->cmd == IPC_INFO && uap->shmid > 0) {
+               /* Can't use the default kern_shmctl interface. */
+               int shmid = uap->shmid;
+               if (shmid > shminfo.shmmni)
+                       shmid = shminfo.shmmni;
+               error = copyout(shmsegs, uap->buf,
+                               shmid * sizeof(struct shmid_ds));
+               td->td_retval[0] = error ? -1 : 0;
+               return (error);
+       }
+#endif /* __CYGWIN__ */
+       
+       error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz);
+       if (error)
+               goto done;
+       
+       /* Cases in which we need to copyout */
+       switch (uap->cmd) {
+       case IPC_INFO:
+       case SHM_INFO:
+       case SHM_STAT:
+       case IPC_STAT:
+               error = copyout(&buf, uap->buf, bufsz);
+               break;
+       }
+
+done:
+       if (error) {
+               /* Invalidate the return value */
+               td->td_retval[0] = -1;
+       }
+       return (error);
+}
+
+
+#ifndef _SYS_SYSPROTO_H_
+struct shmget_args {
+       key_t key;
+       size_t size;
+       int shmflg;
+};
+#endif
+
+static int
+shmget_existing(struct thread *td, struct shmget_args *uap, int mode, int segnum)
+{
+       struct shmid_ds *shmseg;
+       int error;
+
+       shmseg = &shmsegs[segnum];
+       if (shmseg->shm_perm.mode & SHMSEG_REMOVED) {
+               /*
+                * This segment is in the process of being allocated.  Wait
+                * until it's done, and look the key up again (in case the
+                * allocation failed or it was freed).
+                */
+               shmseg->shm_perm.mode |= SHMSEG_WANTED;
+               error = tsleep(shmseg, PLOCK | PCATCH, "shmget", 0);
+               if (error)
+                       return (error);
+               return (EAGAIN);
+       }
+       if ((uap->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL))
+               return (EEXIST);
+       error = ipcperm(td, &shmseg->shm_perm, mode);
+       if (error)
+               return (error);
+       if (uap->size && uap->size > shmseg->shm_segsz)
+               return (EINVAL);
+       td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
+#ifdef __CYGWIN__
+       td->td_retval[1] =
+               vm_object_duplicate(td, shmseg->shm_internal->shm_object);
+#endif /* __CYGWIN__ */
+       return (0);
+}
+
+static int
+shmget_allocate_segment(struct thread *td, struct shmget_args *uap, int mode)
+{
+       int i, segnum, shmid, size;
+#ifndef __CYGWIN__
+       struct ucred *cred = td->td_ucred;
+#endif /* __CYGWIN__ */
+       struct shmid_ds *shmseg;
+       struct shm_handle *shm_handle;
+
+       GIANT_REQUIRED;
+
+       if (uap->size < (unsigned long) shminfo.shmmin ||
+           uap->size > (unsigned long) shminfo.shmmax)
+               return (EINVAL);
+       if (shm_nused >= shminfo.shmmni) /* Any shmids left? */
+               return (ENOSPC);
+       size = round_page(uap->size);
+       if (shm_committed + btoc(size) > (unsigned long) shminfo.shmall)
+               return (ENOMEM);
+       if (shm_last_free < 0) {
+               shmrealloc();   /* Maybe expand the shmsegs[] array. */
+               for (i = 0; i < shmalloced; i++)
+                       if (shmsegs[i].shm_perm.mode & SHMSEG_FREE)
+                               break;
+               if (i == shmalloced)
+                       return (ENOSPC);
+               segnum = i;
+       } else  {
+               segnum = shm_last_free;
+               shm_last_free = -1;
+       }
+       shmseg = &shmsegs[segnum];
+       /*
+        * In case we sleep in malloc(), mark the segment present but deleted
+        * so that noone else tries to create the same key.
+        */
+       shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
+       shmseg->shm_perm.key = uap->key;
+       shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff;
+       shm_handle = (struct shm_handle *)
+           sys_malloc(sizeof(struct shm_handle), M_SHM, M_WAITOK);
+       shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
+       
+       /*
+        * We make sure that we have allocated a pager before we need
+        * to.
+        */
+       if (shm_use_phys) {
+               shm_handle->shm_object =
+                   vm_pager_allocate(OBJT_PHYS, 0, size, VM_PROT_DEFAULT, 0);
+       } else {
+               shm_handle->shm_object =
+                   vm_pager_allocate(OBJT_SWAP, 0, size, VM_PROT_DEFAULT, 0);
+       }
+       VM_OBJECT_LOCK(shm_handle->shm_object);
+       vm_object_clear_flag(shm_handle->shm_object, OBJ_ONEMAPPING);
+       vm_object_set_flag(shm_handle->shm_object, OBJ_NOSPLIT);
+       VM_OBJECT_UNLOCK(shm_handle->shm_object);
+
+       shmseg->shm_internal = shm_handle;
+#ifdef __CYGWIN__
+       shmseg->shm_perm.cuid = shmseg->shm_perm.uid = td->ipcblk->uid;
+       shmseg->shm_perm.cgid = shmseg->shm_perm.gid = td->ipcblk->gid;
+#else
+       shmseg->shm_perm.cuid = shmseg->shm_perm.uid = cred->cr_uid;
+       shmseg->shm_perm.cgid = shmseg->shm_perm.gid = cred->cr_gid;
+#endif /* __CYGWIN__ */
+       shmseg->shm_perm.mode = (shmseg->shm_perm.mode & SHMSEG_WANTED) |
+           (mode & ACCESSPERMS) | SHMSEG_ALLOCATED;
+       shmseg->shm_segsz = uap->size;
+       shmseg->shm_cpid = td->td_proc->p_pid;
+       shmseg->shm_lpid = shmseg->shm_nattch = 0;
+       shmseg->shm_atime = shmseg->shm_dtime = 0;
+       shmseg->shm_ctime = time (NULL);
+       shm_committed += btoc(size);
+       shm_nused++;
+       if (shmseg->shm_perm.mode & SHMSEG_WANTED) {
+               /*
+                * Somebody else wanted this key while we were asleep.  Wake
+                * them up now.
+                */
+               shmseg->shm_perm.mode &= ~SHMSEG_WANTED;
+               wakeup(shmseg);
+       }
+       td->td_retval[0] = shmid;
+#ifdef __CYGWIN__
+       td->td_retval[1] =
+               vm_object_duplicate(td, shmseg->shm_internal->shm_object);
+#endif /* __CYGWIN__ */
+       return (0);
+}
+
+/*
+ * MPSAFE
+ */
+int
+shmget(struct thread *td, struct shmget_args *uap)
+{
+       int segnum, mode;
+       int error;
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+       mtx_lock(&Giant);
+       mode = uap->shmflg & ACCESSPERMS;
+       if (uap->key != IPC_PRIVATE) {
+       again:
+               segnum = shm_find_segment_by_key(uap->key);
+               if (segnum >= 0) {
+                       error = shmget_existing(td, uap, mode, segnum);
+                       if (error == EAGAIN)
+                               goto again;
+                       goto done2;
+               }
+               if ((uap->shmflg & IPC_CREAT) == 0) {
+                       error = ENOENT;
+                       goto done2;
+               }
+       }
+       error = shmget_allocate_segment(td, uap, mode);
+done2:
+#ifdef __CYGWIN__
+       if (!error)
+               ipcexit_creat_hookthread (td);
+#endif
+       mtx_unlock(&Giant);
+       return (error);
+}
+
+#ifndef __CYGWIN__
+/*
+ * MPSAFE
+ */
+int
+shmsys(td, uap)
+       struct thread *td;
+       /* XXX actually varargs. */
+       struct shmsys_args /* {
+               int     which;
+               int     a2;
+               int     a3;
+               int     a4;
+       } */ *uap;
+{
+       int error;
+
+       if (!jail_sysvipc_allowed && jailed(td->td_ucred))
+               return (ENOSYS);
+       if (uap->which < 0 ||
+           uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0]))
+               return (EINVAL);
+       mtx_lock(&Giant);
+       error = (*shmcalls[uap->which])(td, &uap->a2);
+       mtx_unlock(&Giant);
+       return (error);
+}
+#endif /* __CYGWIN__ */
+
+static void
+shmfork_myhook(struct proc *p1, struct proc *p2)
+{
+       struct shmmap_state *shmmap_s;
+       size_t size;
+       int i;
+
+       size = shminfo.shmseg * sizeof(struct shmmap_state);
+       shmmap_s = (struct shmmap_state *) sys_malloc(size, M_SHM, M_WAITOK);
+       bcopy(p1->p_vmspace->vm_shm, shmmap_s, size);
+       p2->p_vmspace->vm_shm = shmmap_s;
+       for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
+               if (shmmap_s->shmid != -1) {
+                       shm_nattch++;
+                       shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++;
+               }
+}
+
+#ifdef __CYGWIN__
+int cygwin_shmfork_myhook (struct thread *td, struct proc *parent)
+{
+  ipcexit_creat_hookthread (td);
+  ipc_p_vmspace (td->ipcblk);
+  ipc_p_vmspace (parent);
+  shmfork_myhook (parent, td->ipcblk);
+  return 0;
+}
+#endif
+
+void
+shmexit_myhook(struct vmspace *vm)
+{
+       struct shmmap_state *base, *shm;
+       int i;
+
+       GIANT_REQUIRED;
+
+       if ((base = vm->vm_shm) != NULL) {
+               vm->vm_shm = NULL;
+               for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) {
+                       if (shm->shmid != -1)
+                               shm_delete_mapping(vm, shm);
+               }
+               sys_free(base, M_SHM);
+       }
+}
+
+static void
+shmrealloc(void)
+{
+       int i;
+       struct shmid_ds *newsegs;
+
+       if (shmalloced >= shminfo.shmmni)
+               return;
+
+       newsegs = (struct shmid_ds *) sys_malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK);
+       if (newsegs == NULL)
+               return;
+       for (i = 0; i < shmalloced; i++)
+               bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
+       for (; i < shminfo.shmmni; i++) {
+               shmsegs[i].shm_perm.mode = SHMSEG_FREE;
+               shmsegs[i].shm_perm.seq = 0;
+       }
+       sys_free(shmsegs, M_SHM);
+       shmsegs = newsegs;
+       shmalloced = shminfo.shmmni;
+}
+
+void
+shminit(void)
+{
+       int i;
+
+       TUNABLE_INT_FETCH("kern.ipc.shmmaxpgs", &shminfo.shmall);
+       for (i = PAGE_SIZE; i > 0; i--) {
+               shminfo.shmmax = shminfo.shmall * PAGE_SIZE;
+               if (shminfo.shmmax >= shminfo.shmall)
+                       break;
+       }
+       TUNABLE_INT_FETCH("kern.ipc.shmmin", &shminfo.shmmin);
+       TUNABLE_INT_FETCH("kern.ipc.shmmni", &shminfo.shmmni);
+       TUNABLE_INT_FETCH("kern.ipc.shmseg", &shminfo.shmseg);
+       TUNABLE_INT_FETCH("kern.ipc.shm_use_phys", &shm_use_phys);
+
+       shmalloced = shminfo.shmmni;
+       shmsegs = (struct shmid_ds *) sys_malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK);
+       if (shmsegs == NULL)
+               panic("cannot allocate initial memory for sysvshm");
+       for (i = 0; i < shmalloced; i++) {
+               shmsegs[i].shm_perm.mode = SHMSEG_FREE;
+               shmsegs[i].shm_perm.seq = 0;
+       }
+       shm_last_free = 0;
+       shm_nused = 0;
+       shm_committed = 0;
+#ifndef __CYGWIN__
+       shmexit_hook = &shmexit_myhook;
+       shmfork_hook = &shmfork_myhook;
+#endif /* __CYGWIN__ */
+}
+
+int
+shmunload(void)
+{
+
+       if (shm_nused > 0)
+               return (EBUSY);
+
+       sys_free(shmsegs, M_SHM);
+#ifndef __CYGWIN__
+       shmexit_hook = NULL;
+       shmfork_hook = NULL;
+#endif /* __CYGWIN__ */
+       return (0);
+}
+
+#ifndef __CYGWIN__
+static int
+sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
+{
+
+       return (SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0])));
+}
+
+static int
+sysvshm_modload(struct module *module, int cmd, void *arg)
+{
+       int error = 0;
+
+       switch (cmd) {
+       case MOD_LOAD:
+               shminit();
+               break;
+       case MOD_UNLOAD:
+               error = shmunload();
+               break;
+       case MOD_SHUTDOWN:
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+       return (error);
+}
+
+static moduledata_t sysvshm_mod = {
+       "sysvshm",
+       &sysvshm_modload,
+       NULL
+};
+
+SYSCALL_MODULE_HELPER(shmsys);
+SYSCALL_MODULE_HELPER(shmat);
+SYSCALL_MODULE_HELPER(shmctl);
+SYSCALL_MODULE_HELPER(shmdt);
+SYSCALL_MODULE_HELPER(shmget);
+
+DECLARE_MODULE(sysvshm, sysvshm_mod,
+       SI_SUB_SYSV_SHM, SI_ORDER_FIRST);
+MODULE_VERSION(sysvshm, 1);
+#endif /* __CYGWIN__ */
+#endif /* __OUTSIDE_CYGWIN__ */
index ba0fe41..53dd6fa 100644 (file)
@@ -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__ */
index 2c7100d..a52bb60 100644 (file)
@@ -1,6 +1,6 @@
-/* cygserver_transport.cc
+/* transport.cc
 
-   Copyright 2001, 2002 Red Hat Inc.
+   Copyright 2001, 2002, 2003 Red Hat Inc.
 
    Written by Robert Collins <rbtcollins@hotmail.com>
 
@@ -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__ */
 
similarity index 75%
rename from winsup/cygserver/cygserver_transport.h
rename to winsup/cygserver/transport.h
index 915f35e..76018d2 100644 (file)
@@ -1,6 +1,6 @@
-/* cygserver_transport.h
+/* transport.h
 
-   Copyright 2001, 2002 Red Hat Inc.
+   Copyright 2001, 2002, 2003 Red Hat Inc.
 
    Written by Robert Collins <rbtcollins@hotmail.com>
 
@@ -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 */
index 5fd1158..5f8ceec 100644 (file)
@@ -1,6 +1,6 @@
-/* cygserver_transport_pipes.cc
+/* transport_pipes.cc
 
-   Copyright 2001, 2002 Red Hat Inc.
+   Copyright 2001, 2002, 2003 Red Hat Inc.
 
    Written by Robert Collins <rbtcollins@hotmail.com>
 
@@ -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__ */
similarity index 67%
rename from winsup/cygserver/cygserver_transport_pipes.h
rename to winsup/cygserver/transport_pipes.h
index 4bea2eb..7265a88 100644 (file)
@@ -1,6 +1,6 @@
-/* cygserver_transport_pipes.h
+/* transport_pipes.h
 
-   Copyright 2001, 2002 Red Hat Inc.
+   Copyright 2001, 2002, 2003 Red Hat Inc.
 
    Written by Robert Collins <rbtcollins@hotmail.com>
 
@@ -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 */
index 78d237a..f3668f6 100644 (file)
@@ -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__ */
similarity index 86%
rename from winsup/cygserver/cygserver_transport_sockets.h
rename to winsup/cygserver/transport_sockets.h
index d960f9c..d684a87 100644 (file)
@@ -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 */
index cb67c78..39db639 100644 (file)
@@ -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__);  \
-    } while (false)
-
-#define __noop_printf(...) do {;} while (false)
-
-#else /* !NEW_MACRO_VARARGS */
-
-#define system_printf(args...)                                 \
-  do                                                           \
-    {                                                          \
-      __cygserver__printf (__PRETTY_FUNCTION__, ## 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(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__)