Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2003-11-19 21:49:41 +0300
committerCorinna Vinschen <corinna@vinschen.de>2003-11-19 21:49:41 +0300
commit282113ba894449ed17e85b296cf0760d5206ac8d (patch)
tree830bd7ad49e085ea8cde78fea68848fbbca09880
parent64cfc6f213541f0e9e8e57011af8a56aca8c8216 (diff)
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.
-rw-r--r--winsup/cygserver/ChangeLog73
-rw-r--r--winsup/cygserver/Makefile.in29
-rw-r--r--winsup/cygserver/bsd_helper.cc694
-rw-r--r--winsup/cygserver/bsd_helper.h63
-rw-r--r--winsup/cygserver/bsd_log.cc95
-rw-r--r--winsup/cygserver/bsd_log.h33
-rw-r--r--winsup/cygserver/bsd_mutex.cc253
-rw-r--r--winsup/cygserver/bsd_mutex.h51
-rw-r--r--winsup/cygserver/client.cc190
-rw-r--r--winsup/cygserver/cygserver.cc463
-rw-r--r--winsup/cygserver/cygserver.conf126
-rw-r--r--winsup/cygserver/msg.cc123
-rw-r--r--winsup/cygserver/process.cc16
-rw-r--r--winsup/cygserver/process.h (renamed from winsup/cygserver/cygserver_process.h)8
-rw-r--r--winsup/cygserver/sem.cc107
-rw-r--r--winsup/cygserver/shm.cc918
-rw-r--r--winsup/cygserver/sysv_msg.cc1208
-rw-r--r--winsup/cygserver/sysv_sem.cc1323
-rw-r--r--winsup/cygserver/sysv_shm.cc1025
-rw-r--r--winsup/cygserver/threaded_queue.cc8
-rw-r--r--winsup/cygserver/transport.cc28
-rw-r--r--winsup/cygserver/transport.h (renamed from winsup/cygserver/cygserver_transport.h)14
-rw-r--r--winsup/cygserver/transport_pipes.cc59
-rw-r--r--winsup/cygserver/transport_pipes.h (renamed from winsup/cygserver/cygserver_transport_pipes.h)20
-rw-r--r--winsup/cygserver/transport_sockets.cc8
-rw-r--r--winsup/cygserver/transport_sockets.h (renamed from winsup/cygserver/cygserver_transport_sockets.h)8
-rw-r--r--winsup/cygserver/woutsup.h81
27 files changed, 5656 insertions, 1368 deletions
diff --git a/winsup/cygserver/ChangeLog b/winsup/cygserver/ChangeLog
index cb76730c4..5b9dd13c6 100644
--- a/winsup/cygserver/ChangeLog
+++ b/winsup/cygserver/ChangeLog
@@ -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
diff --git a/winsup/cygserver/Makefile.in b/winsup/cygserver/Makefile.in
index 767fcaa1f..0dd11207f 100644
--- a/winsup/cygserver/Makefile.in
+++ b/winsup/cygserver/Makefile.in
@@ -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
index 000000000..42afd548f
--- /dev/null
+++ b/winsup/cygserver/bsd_helper.cc
@@ -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
index 000000000..14849e918
--- /dev/null
+++ b/winsup/cygserver/bsd_helper.h
@@ -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
index 000000000..5cf1c848e
--- /dev/null
+++ b/winsup/cygserver/bsd_log.cc
@@ -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
index 000000000..48573182a
--- /dev/null
+++ b/winsup/cygserver/bsd_log.h
@@ -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
index 000000000..9c7485b7f
--- /dev/null
+++ b/winsup/cygserver/bsd_mutex.cc
@@ -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
index 000000000..3b07bf3c6
--- /dev/null
+++ b/winsup/cygserver/bsd_mutex.h
@@ -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 */
diff --git a/winsup/cygserver/client.cc b/winsup/cygserver/client.cc
index 600ddbd67..d8f7ac55a 100644
--- a/winsup/cygserver/client.cc
+++ b/winsup/cygserver/client.cc
@@ -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__ */
diff --git a/winsup/cygserver/cygserver.cc b/winsup/cygserver/cygserver.cc
index f152fc588..d38d12eee 100644
--- a/winsup/cygserver/cygserver.cc
+++ b/winsup/cygserver/cygserver.cc
@@ -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
index 000000000..b7db6bbcf
--- /dev/null
+++ b/winsup/cygserver/cygserver.conf
@@ -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
diff --git a/winsup/cygserver/msg.cc b/winsup/cygserver/msg.cc
index fecaa068a..713a5866a 100644
--- a/winsup/cygserver/msg.cc
+++ b/winsup/cygserver/msg.cc
@@ -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__ */
diff --git a/winsup/cygserver/process.cc b/winsup/cygserver/process.cc
index aa8294f57..0f6e0cb5f 100644
--- a/winsup/cygserver/process.cc
+++ b/winsup/cygserver/process.cc
@@ -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 *
diff --git a/winsup/cygserver/cygserver_process.h b/winsup/cygserver/process.h
index 25c634e9e..142b3634c 100644
--- a/winsup/cygserver/cygserver_process.h
+++ b/winsup/cygserver/process.h
@@ -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 */
diff --git a/winsup/cygserver/sem.cc b/winsup/cygserver/sem.cc
index 97d91a354..6a179b0b6 100644
--- a/winsup/cygserver/sem.cc
+++ b/winsup/cygserver/sem.cc
@@ -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__ */
diff --git a/winsup/cygserver/shm.cc b/winsup/cygserver/shm.cc
index 50d2b6e1d..f73fd012a 100644
--- a/winsup/cygserver/shm.cc
+++ b/winsup/cygserver/shm.cc
@@ -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
index 000000000..9c1049c97
--- /dev/null
+++ b/winsup/cygserver/sysv_msg.cc
@@ -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
index 000000000..ac5efcdaa
--- /dev/null
+++ b/winsup/cygserver/sysv_sem.cc
@@ -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
index 000000000..70ed1a3d4
--- /dev/null
+++ b/winsup/cygserver/sysv_shm.cc
@@ -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__ */
diff --git a/winsup/cygserver/threaded_queue.cc b/winsup/cygserver/threaded_queue.cc
index ba0fe4178..53dd6fa11 100644
--- a/winsup/cygserver/threaded_queue.cc
+++ b/winsup/cygserver/threaded_queue.cc
@@ -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__ */
diff --git a/winsup/cygserver/transport.cc b/winsup/cygserver/transport.cc
index 2c7100d77..a52bb60e7 100644
--- a/winsup/cygserver/transport.cc
+++ b/winsup/cygserver/transport.cc
@@ -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__ */
diff --git a/winsup/cygserver/cygserver_transport.h b/winsup/cygserver/transport.h
index 915f35e66..76018d20e 100644
--- a/winsup/cygserver/cygserver_transport.h
+++ b/winsup/cygserver/transport.h
@@ -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 */
diff --git a/winsup/cygserver/transport_pipes.cc b/winsup/cygserver/transport_pipes.cc
index 5fd11581d..5f8ceec4d 100644
--- a/winsup/cygserver/transport_pipes.cc
+++ b/winsup/cygserver/transport_pipes.cc
@@ -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__ */
diff --git a/winsup/cygserver/cygserver_transport_pipes.h b/winsup/cygserver/transport_pipes.h
index 4bea2eb13..7265a88f8 100644
--- a/winsup/cygserver/cygserver_transport_pipes.h
+++ b/winsup/cygserver/transport_pipes.h
@@ -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 */
diff --git a/winsup/cygserver/transport_sockets.cc b/winsup/cygserver/transport_sockets.cc
index 78d237adc..f3668f6d8 100644
--- a/winsup/cygserver/transport_sockets.cc
+++ b/winsup/cygserver/transport_sockets.cc
@@ -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__ */
diff --git a/winsup/cygserver/cygserver_transport_sockets.h b/winsup/cygserver/transport_sockets.h
index d960f9c2c..d684a87c9 100644
--- a/winsup/cygserver/cygserver_transport_sockets.h
+++ b/winsup/cygserver/transport_sockets.h
@@ -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 */
diff --git a/winsup/cygserver/woutsup.h b/winsup/cygserver/woutsup.h
index cb67c78d4..39db63997 100644
--- a/winsup/cygserver/woutsup.h
+++ b/winsup/cygserver/woutsup.h
@@ -1,6 +1,6 @@
/* woutsup.h: for Cygwin code compiled outside the DLL (i.e. cygserver).
- Copyright 2002 Red Hat, Inc.
+ Copyright 2002, 2003 Red Hat, Inc.
This file is part of Cygwin.
@@ -42,67 +42,32 @@ details. */
#include "wincap.h"
+#include "bsd_helper.h"
+#include "bsd_log.h"
+#include "bsd_mutex.h"
+
/* The one function we use from winuser.h most of the time */
extern "C" DWORD WINAPI GetLastError (void);
extern int cygserver_running;
-#if !defined(__STDC_VERSION__) || __STDC_VERSION__ >= 199900L
-#define NEW_MACRO_VARARGS
-#endif
-
-/*
- * A reproduction of the <sys/strace.h> macros. This allows code that
- * runs both inside and outside the Cygwin DLL to use the same macros
- * for logging messages.
- */
-
-extern "C" void __cygserver__printf (const char *, const char *, ...);
-
-#ifdef NEW_MACRO_VARARGS
-
-#define system_printf(...) \
- do \
- { \
- __cygserver__printf (__PRETTY_FUNCTION__, __VA_ARGS__); \
- } 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__)