Don't use safe_new but new throughout. Fix copyright dates
throughout. * Makefile.in: Accomodate all new files and name changes. Add a *.d dependency. (sbindir): Add. (etcdir): Drop in favor of more appropriate sysconfdir definition. (sysconfdir): Add. (CXXFLAGS): Add -MMD flag. Add SYSCONFDIR definition. (.SUFFIXES): Add. (install): Add action items. (libclean): New target. (fullclean): Ditto. * bsd_helper.cc: New file. * bsd_helper.h: Ditto. * bsd_log.cc: Ditto. * bsd_log.h: Ditto. * bsd_mutex.cc: Ditto. * bsd_mutex.h: Ditto. * client.cc: Rearrange to build as less as possible if __INSIDE_CYGWIN__. (client_request::handle_request): Add Message Queue and Semaphore handling. * cygserver.cc: Rearrange to build as less as possible if __INSIDE_CYGWIN__. Use new debug/log/panic logging functions. (DEF_CONFIG_FILE): New definition for configuration file. Use throughout. (getfunc): Remove. (__cygserver__printf): Remove. (client_request_attach_tty::serve): Return error if impersonation fails. (print_usage): Pump up help message. (print_version): Add output of default configuration file. (main): Accommodate new options. Allow overwrite of threading options from config file. Call several new initialization functions. Drop printing dots. Don't define SIGHANDLE inline. * cygserver.conf: New file. * cygserver_process.h: Rename to process.h. * cygserver_transport.h: Rename to transport.h. * cygserver_transport_pipes.h: Rename to transport_pipes.h. * cygserver_transport_sockets.h: Rename to transport_sockets.h. * msg.cc: Rewrite. * sem.cc: Rewrite. * shm.cc: Rewrite. * sysv_msg.cc: New file, derived from FreeBSD version 1.52. * sysv_sem.cc: New file, derived from FreeBSD version 1.66. * sysv_shm.cc: New file, derived from FreeBSD version 1.89. * threaded_queue.cc: Rearrange to build as less as possible if __INSIDE_CYGWIN__. * transport.cc (transport_layer_base::impersonate_client): Define bool. (transport_layer_base::revert_to_self): Ditto. * transport.h (transport_layer_base::impersonate_client): Declare bool. (transport_layer_base::revert_to_self): Ditto. * transport_pipes.cc (transport_layer_pipes::transport_layer_pipes): Don't call init_security. (init_security): Remove. (transport_layer_pipes::accept): Use global sec_all_nih. (transport_layer_pipes::connect): Ditto. (transport_layer_pipes::impersonate_client): Define bool. (transport_layer_pipes::revert_to_self): Ditt. * transport_pipes.h (transport_layer_pipes::impersonate_client): Declare bool. (transport_layer_pipes::revert_to_self): Ditto. * woutsup.h: Include bsd compatibility headers. (SIGHANDLE): Add definition. (__cygserver__printf): Remove definition. (__noop_printf): Ditto. (debug_printf): Define using debug. (syscall_printf): Define using log. (system_printf): Ditto. Drop all other _printf definitions.
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin.
|
||||
/* shm.cc: Single unix specification IPC interface for Cygwin.
|
||||
|
||||
Copyright 2002 Red Hat, Inc.
|
||||
|
||||
Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
|
||||
Based on code by Robert Collins <robert.collins@hotmail.com>.
|
||||
Copyright 2003 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
@@ -11,824 +8,33 @@ This software is a copyrighted work licensed under the terms of the
|
||||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#ifdef __OUTSIDE_CYGWIN__
|
||||
#include "woutsup.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "cygserver.h"
|
||||
#include "process.h"
|
||||
#include "transport.h"
|
||||
|
||||
#include "cygserver_ipc.h"
|
||||
#include "cygserver_shm.h"
|
||||
#include "security.h"
|
||||
|
||||
#include "cygserver.h"
|
||||
#include "cygserver_process.h"
|
||||
#include "cygserver_transport.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* class server_shmmgr
|
||||
*
|
||||
* A singleton class.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#define shmmgr (server_shmmgr::instance ())
|
||||
|
||||
class server_shmmgr
|
||||
{
|
||||
private:
|
||||
class attach_t
|
||||
{
|
||||
public:
|
||||
class process *const _client;
|
||||
unsigned int _refcnt;
|
||||
|
||||
attach_t *_next;
|
||||
|
||||
attach_t (class process *const client)
|
||||
: _client (client),
|
||||
_refcnt (0),
|
||||
_next (NULL)
|
||||
{}
|
||||
};
|
||||
|
||||
class segment_t
|
||||
{
|
||||
private:
|
||||
// Bits for the _flg field.
|
||||
enum { IS_DELETED = 0x01 };
|
||||
|
||||
public:
|
||||
const int _intid;
|
||||
const int _shmid;
|
||||
struct shmid_ds _ds;
|
||||
|
||||
segment_t *_next;
|
||||
|
||||
segment_t (const key_t key, const int intid, const HANDLE hFileMap);
|
||||
~segment_t ();
|
||||
|
||||
bool is_deleted () const
|
||||
{
|
||||
return _flg & IS_DELETED;
|
||||
}
|
||||
|
||||
bool is_pending_delete () const
|
||||
{
|
||||
return !_ds.shm_nattch && is_deleted ();
|
||||
}
|
||||
|
||||
void mark_deleted ()
|
||||
{
|
||||
assert (!is_deleted ());
|
||||
|
||||
_flg |= IS_DELETED;
|
||||
}
|
||||
|
||||
int attach (class process *, HANDLE & hFileMap);
|
||||
int detach (class process *);
|
||||
|
||||
private:
|
||||
static long _sequence;
|
||||
|
||||
int _flg;
|
||||
const HANDLE _hFileMap;
|
||||
attach_t *_attach_head; // A list sorted by winpid;
|
||||
|
||||
attach_t *find (const class process *, attach_t **previous = NULL);
|
||||
};
|
||||
|
||||
class cleanup_t : public cleanup_routine
|
||||
{
|
||||
public:
|
||||
cleanup_t (const segment_t *const segptr)
|
||||
: cleanup_routine (reinterpret_cast<void *> (segptr->_shmid))
|
||||
{
|
||||
assert (key ());
|
||||
}
|
||||
|
||||
int shmid () const { return reinterpret_cast<int> (key ()); }
|
||||
|
||||
virtual void cleanup (class process *const client)
|
||||
{
|
||||
const int res = shmmgr.shmdt (shmid (), client);
|
||||
|
||||
if (res != 0)
|
||||
debug_printf ("process cleanup failed [shmid = %d]: %s",
|
||||
shmid (), strerror (-res));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static server_shmmgr & instance ();
|
||||
|
||||
int shmat (HANDLE & hFileMap,
|
||||
int shmid, int shmflg, class process *);
|
||||
int shmctl (int & out_shmid, struct shmid_ds & out_ds,
|
||||
struct shminfo & out_shminfo, struct shm_info & out_shm_info,
|
||||
const int shmid, int cmd, const struct shmid_ds &,
|
||||
class process *);
|
||||
int shmdt (int shmid, class process *);
|
||||
int shmget (int & out_shmid, key_t, size_t, int shmflg, uid_t, gid_t,
|
||||
class process *);
|
||||
|
||||
private:
|
||||
static server_shmmgr *_instance;
|
||||
static pthread_once_t _instance_once;
|
||||
|
||||
static void initialise_instance ();
|
||||
|
||||
CRITICAL_SECTION _segments_lock;
|
||||
segment_t *_segments_head; // A list sorted by int_id.
|
||||
|
||||
int _shm_ids; // Number of shm segments (for ipcs(8)).
|
||||
int _shm_tot; // Total bytes of shm segments (for ipcs(8)).
|
||||
int _shm_atts; // Number of attached segments (for ipcs(8)).
|
||||
int _intid_max; // Highest intid yet allocated (for ipcs(8)).
|
||||
|
||||
server_shmmgr ();
|
||||
~server_shmmgr ();
|
||||
|
||||
// Undefined (as this class is a singleton):
|
||||
server_shmmgr (const server_shmmgr &);
|
||||
server_shmmgr & operator= (const server_shmmgr &);
|
||||
|
||||
segment_t *find_by_key (key_t);
|
||||
segment_t *find (int intid, segment_t **previous = NULL);
|
||||
|
||||
int new_segment (key_t, size_t, int shmflg, pid_t, uid_t, gid_t);
|
||||
|
||||
segment_t *new_segment (key_t, size_t, HANDLE);
|
||||
void delete_segment (segment_t *);
|
||||
};
|
||||
|
||||
/* static */ long server_shmmgr::segment_t::_sequence = 0;
|
||||
|
||||
/* static */ server_shmmgr *server_shmmgr::_instance = NULL;
|
||||
/* static */ pthread_once_t server_shmmgr::_instance_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::segment_t::segment_t ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::segment_t::segment_t (const key_t key,
|
||||
const int intid,
|
||||
const HANDLE hFileMap)
|
||||
: _intid (intid),
|
||||
_shmid (ipc_int2ext (intid, IPC_SHMOP, _sequence)),
|
||||
_next (NULL),
|
||||
_flg (0),
|
||||
_hFileMap (hFileMap),
|
||||
_attach_head (NULL)
|
||||
{
|
||||
assert (0 <= _intid && _intid < SHMMNI);
|
||||
|
||||
memset (&_ds, '\0', sizeof (_ds));
|
||||
_ds.shm_perm.key = key;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::segment_t::~segment_t ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::segment_t::~segment_t ()
|
||||
{
|
||||
assert (!_attach_head);
|
||||
|
||||
if (!CloseHandle (_hFileMap))
|
||||
syscall_printf ("failed to close file map [handle = 0x%x]: %E", _hFileMap);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::segment_t::attach ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::segment_t::attach (class process *const client,
|
||||
HANDLE & hFileMap)
|
||||
{
|
||||
assert (client);
|
||||
|
||||
if (!DuplicateHandle (GetCurrentProcess (),
|
||||
_hFileMap,
|
||||
client->handle (),
|
||||
&hFileMap,
|
||||
0,
|
||||
FALSE, // bInheritHandle
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
syscall_printf (("failed to duplicate handle for client "
|
||||
"[key = 0x%016llx, shmid = %d, handle = 0x%x]: %E"),
|
||||
_ds.shm_perm.key, _shmid, _hFileMap);
|
||||
|
||||
return -EACCES; // FIXME: Case analysis?
|
||||
}
|
||||
|
||||
_ds.shm_lpid = client->cygpid ();
|
||||
_ds.shm_nattch += 1;
|
||||
_ds.shm_atime = time (NULL); // FIXME: sub-second times.
|
||||
|
||||
attach_t *previous = NULL;
|
||||
attach_t *attptr = find (client, &previous);
|
||||
|
||||
if (!attptr)
|
||||
{
|
||||
attptr = safe_new (attach_t, client);
|
||||
|
||||
if (previous)
|
||||
{
|
||||
attptr->_next = previous->_next;
|
||||
previous->_next = attptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
attptr->_next = _attach_head;
|
||||
_attach_head = attptr;
|
||||
}
|
||||
}
|
||||
|
||||
attptr->_refcnt += 1;
|
||||
|
||||
cleanup_t *const cleanup = safe_new (cleanup_t, this);
|
||||
|
||||
// FIXME: ::add should only fail if the process object is already
|
||||
// cleaning up; but it can't be doing that since this thread has it
|
||||
// locked.
|
||||
|
||||
const bool result = client->add (cleanup);
|
||||
|
||||
assert (result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::segment_t::detach ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::segment_t::detach (class process *const client)
|
||||
{
|
||||
attach_t *previous = NULL;
|
||||
attach_t *const attptr = find (client, &previous);
|
||||
|
||||
if (!attptr)
|
||||
return -EINVAL;
|
||||
|
||||
if (client->is_active ())
|
||||
{
|
||||
const cleanup_t key (this);
|
||||
|
||||
if (!client->remove (&key))
|
||||
syscall_printf (("failed to remove cleanup routine for %d(%lu) "
|
||||
"[shmid = %d]"),
|
||||
client->cygpid (), client->winpid (),
|
||||
_shmid);
|
||||
}
|
||||
|
||||
attptr->_refcnt -= 1;
|
||||
|
||||
if (!attptr->_refcnt)
|
||||
{
|
||||
assert (previous ? previous->_next == attptr : _attach_head == attptr);
|
||||
|
||||
if (previous)
|
||||
previous->_next = attptr->_next;
|
||||
else
|
||||
_attach_head = attptr->_next;
|
||||
|
||||
safe_delete (attptr);
|
||||
}
|
||||
|
||||
assert (_ds.shm_nattch > 0);
|
||||
|
||||
_ds.shm_lpid = client->cygpid ();
|
||||
_ds.shm_nattch -= 1;
|
||||
_ds.shm_dtime = time (NULL); // FIXME: sub-second times.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::segment_t::find ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::attach_t *
|
||||
server_shmmgr::segment_t::find (const class process *const client,
|
||||
attach_t **previous)
|
||||
{
|
||||
if (previous)
|
||||
*previous = NULL;
|
||||
|
||||
// Nb. The _attach_head list is sorted by winpid.
|
||||
|
||||
for (attach_t *attptr = _attach_head; attptr; attptr = attptr->_next)
|
||||
if (attptr->_client == client)
|
||||
return attptr;
|
||||
else if (attptr->_client->winpid () > client->winpid ())
|
||||
return NULL;
|
||||
else if (previous)
|
||||
*previous = attptr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::instance ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
/* static */ server_shmmgr &
|
||||
server_shmmgr::instance ()
|
||||
{
|
||||
pthread_once (&_instance_once, &initialise_instance);
|
||||
|
||||
assert (_instance);
|
||||
|
||||
return *_instance;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::shmat ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::shmat (HANDLE & hFileMap,
|
||||
const int shmid, const int shmflg,
|
||||
class process *const client)
|
||||
{
|
||||
syscall_printf ("shmat (shmid = %d, shmflg = 0%o) for %d(%lu)",
|
||||
shmid, shmflg, client->cygpid (), client->winpid ());
|
||||
|
||||
int result = 0;
|
||||
EnterCriticalSection (&_segments_lock);
|
||||
|
||||
segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP));
|
||||
|
||||
if (!segptr)
|
||||
result = -EINVAL;
|
||||
else
|
||||
result = segptr->attach (client, hFileMap);
|
||||
|
||||
if (!result)
|
||||
_shm_atts += 1;
|
||||
|
||||
LeaveCriticalSection (&_segments_lock);
|
||||
|
||||
if (result < 0)
|
||||
syscall_printf (("-1 [%d] = shmat (shmid = %d, shmflg = 0%o) "
|
||||
"for %d(%lu)"),
|
||||
-result, shmid, shmflg,
|
||||
client->cygpid (), client->winpid ());
|
||||
else
|
||||
syscall_printf (("0x%x = shmat (shmid = %d, shmflg = 0%o) "
|
||||
"for %d(%lu)"),
|
||||
hFileMap, shmid, shmflg,
|
||||
client->cygpid (), client->winpid ());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::shmctl ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::shmctl (int & out_shmid,
|
||||
struct shmid_ds & out_ds,
|
||||
struct shminfo & out_shminfo,
|
||||
struct shm_info & out_shm_info,
|
||||
const int shmid, const int cmd,
|
||||
const struct shmid_ds & ds,
|
||||
class process *const client)
|
||||
{
|
||||
syscall_printf ("shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)",
|
||||
shmid, cmd, client->cygpid (), client->winpid ());
|
||||
|
||||
int result = 0;
|
||||
EnterCriticalSection (&_segments_lock);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case IPC_STAT:
|
||||
case SHM_STAT: // Uses intids rather than shmids.
|
||||
case IPC_SET:
|
||||
case IPC_RMID:
|
||||
{
|
||||
int intid;
|
||||
|
||||
if (cmd == SHM_STAT)
|
||||
intid = shmid;
|
||||
else
|
||||
intid = ipc_ext2int (shmid, IPC_SHMOP);
|
||||
|
||||
segment_t *const segptr = find (intid);
|
||||
|
||||
if (!segptr)
|
||||
result = -EINVAL;
|
||||
else
|
||||
switch (cmd)
|
||||
{
|
||||
case IPC_STAT:
|
||||
out_ds = segptr->_ds;
|
||||
break;
|
||||
|
||||
case IPC_SET:
|
||||
segptr->_ds.shm_perm.uid = ds.shm_perm.uid;
|
||||
segptr->_ds.shm_perm.gid = ds.shm_perm.gid;
|
||||
segptr->_ds.shm_perm.mode = ds.shm_perm.mode & 0777;
|
||||
segptr->_ds.shm_lpid = client->cygpid ();
|
||||
segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times.
|
||||
break;
|
||||
|
||||
case IPC_RMID:
|
||||
if (segptr->is_deleted ())
|
||||
result = -EIDRM;
|
||||
else
|
||||
{
|
||||
segptr->mark_deleted ();
|
||||
if (segptr->is_pending_delete ())
|
||||
delete_segment (segptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case SHM_STAT: // ipcs(8) i'face.
|
||||
out_ds = segptr->_ds;
|
||||
out_shmid = segptr->_shmid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IPC_INFO:
|
||||
out_shminfo.shmmax = SHMMAX;
|
||||
out_shminfo.shmmin = SHMMIN;
|
||||
out_shminfo.shmmni = SHMMNI;
|
||||
out_shminfo.shmseg = SHMSEG;
|
||||
out_shminfo.shmall = SHMALL;
|
||||
break;
|
||||
|
||||
case SHM_INFO: // ipcs(8) i'face.
|
||||
out_shmid = _intid_max;
|
||||
out_shm_info.shm_ids = _shm_ids;
|
||||
out_shm_info.shm_tot = _shm_tot;
|
||||
out_shm_info.shm_atts = _shm_atts;
|
||||
break;
|
||||
|
||||
default:
|
||||
result = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
LeaveCriticalSection (&_segments_lock);
|
||||
|
||||
if (result < 0)
|
||||
syscall_printf (("-1 [%d] = "
|
||||
"shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"),
|
||||
-result,
|
||||
shmid, cmd, client->cygpid (), client->winpid ());
|
||||
else
|
||||
syscall_printf (("%d = "
|
||||
"shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"),
|
||||
((cmd == SHM_STAT || cmd == SHM_INFO)
|
||||
? out_shmid
|
||||
: result),
|
||||
shmid, cmd, client->cygpid (), client->winpid ());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::shmdt ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::shmdt (const int shmid, class process *const client)
|
||||
{
|
||||
syscall_printf ("shmdt (shmid = %d) for %d(%lu)",
|
||||
shmid, client->cygpid (), client->winpid ());
|
||||
|
||||
int result = 0;
|
||||
EnterCriticalSection (&_segments_lock);
|
||||
|
||||
segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP));
|
||||
|
||||
if (!segptr)
|
||||
result = -EINVAL;
|
||||
else
|
||||
result = segptr->detach (client);
|
||||
|
||||
if (!result)
|
||||
_shm_atts -= 1;
|
||||
|
||||
if (!result && segptr->is_pending_delete ())
|
||||
delete_segment (segptr);
|
||||
|
||||
LeaveCriticalSection (&_segments_lock);
|
||||
|
||||
if (result < 0)
|
||||
syscall_printf ("-1 [%d] = shmdt (shmid = %d) for %d(%lu)",
|
||||
-result, shmid, client->cygpid (), client->winpid ());
|
||||
else
|
||||
syscall_printf ("%d = shmdt (shmid = %d) for %d(%lu)",
|
||||
result, shmid, client->cygpid (), client->winpid ());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::shmget ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::shmget (int & out_shmid,
|
||||
const key_t key, const size_t size, const int shmflg,
|
||||
const uid_t uid, const gid_t gid,
|
||||
class process *const client)
|
||||
{
|
||||
syscall_printf (("shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
|
||||
"for %d(%lu)"),
|
||||
key, size, shmflg,
|
||||
client->cygpid (), client->winpid ());
|
||||
|
||||
int result = 0;
|
||||
EnterCriticalSection (&_segments_lock);
|
||||
|
||||
if (key == IPC_PRIVATE)
|
||||
result = new_segment (key, size, shmflg,
|
||||
client->cygpid (), uid, gid);
|
||||
else
|
||||
{
|
||||
segment_t *const segptr = find_by_key (key);
|
||||
|
||||
if (!segptr)
|
||||
if (shmflg & IPC_CREAT)
|
||||
result = new_segment (key, size, shmflg,
|
||||
client->cygpid (), uid, gid);
|
||||
else
|
||||
result = -ENOENT;
|
||||
else if (segptr->is_deleted ())
|
||||
result = -EIDRM;
|
||||
else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
|
||||
result = -EEXIST;
|
||||
else if ((shmflg & ~(segptr->_ds.shm_perm.mode)) & 0777)
|
||||
result = -EACCES;
|
||||
else if (size && segptr->_ds.shm_segsz < size)
|
||||
result = -EINVAL;
|
||||
else
|
||||
result = segptr->_shmid;
|
||||
}
|
||||
|
||||
LeaveCriticalSection (&_segments_lock);
|
||||
|
||||
if (result >= 0)
|
||||
{
|
||||
out_shmid = result;
|
||||
result = 0;
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
syscall_printf (("-1 [%d] = "
|
||||
"shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
|
||||
"for %d(%lu)"),
|
||||
-result,
|
||||
key, size, shmflg,
|
||||
client->cygpid (), client->winpid ());
|
||||
else
|
||||
syscall_printf (("%d = "
|
||||
"shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
|
||||
"for %d(%lu)"),
|
||||
out_shmid,
|
||||
key, size, shmflg,
|
||||
client->cygpid (), client->winpid ());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::initialise_instance ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
/* static */ void
|
||||
server_shmmgr::initialise_instance ()
|
||||
{
|
||||
assert (!_instance);
|
||||
|
||||
_instance = safe_new0 (server_shmmgr);
|
||||
|
||||
assert (_instance);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::server_shmmgr ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::server_shmmgr ()
|
||||
: _segments_head (NULL),
|
||||
_shm_ids (0),
|
||||
_shm_tot (0),
|
||||
_shm_atts (0),
|
||||
_intid_max (0)
|
||||
{
|
||||
InitializeCriticalSection (&_segments_lock);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::~server_shmmgr ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::~server_shmmgr ()
|
||||
{
|
||||
DeleteCriticalSection (&_segments_lock);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::find_by_key ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::segment_t *
|
||||
server_shmmgr::find_by_key (const key_t key)
|
||||
{
|
||||
for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next)
|
||||
if (segptr->_ds.shm_perm.key == key)
|
||||
return segptr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::find ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::segment_t *
|
||||
server_shmmgr::find (const int intid, segment_t **previous)
|
||||
{
|
||||
if (previous)
|
||||
*previous = NULL;
|
||||
|
||||
for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next)
|
||||
if (segptr->_intid == intid)
|
||||
return segptr;
|
||||
else if (segptr->_intid > intid) // The list is sorted by intid.
|
||||
return NULL;
|
||||
else if (previous)
|
||||
*previous = segptr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::new_segment ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::new_segment (const key_t key,
|
||||
const size_t size,
|
||||
const int shmflg,
|
||||
const pid_t cygpid,
|
||||
const uid_t uid,
|
||||
const gid_t gid)
|
||||
{
|
||||
if (size < SHMMIN || size > SHMMAX)
|
||||
return -EINVAL;
|
||||
|
||||
const HANDLE hFileMap = CreateFileMapping (INVALID_HANDLE_VALUE,
|
||||
NULL, PAGE_READWRITE,
|
||||
0, size,
|
||||
NULL);
|
||||
|
||||
if (!hFileMap)
|
||||
{
|
||||
syscall_printf ("failed to create file mapping [size = %lu]: %E", size);
|
||||
return -ENOMEM; // FIXME
|
||||
}
|
||||
|
||||
segment_t *const segptr = new_segment (key, size, hFileMap);
|
||||
|
||||
if (!segptr)
|
||||
{
|
||||
(void) CloseHandle (hFileMap);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
segptr->_ds.shm_perm.cuid = segptr->_ds.shm_perm.uid = uid;
|
||||
segptr->_ds.shm_perm.cgid = segptr->_ds.shm_perm.gid = gid;
|
||||
segptr->_ds.shm_perm.mode = shmflg & 0777;
|
||||
segptr->_ds.shm_segsz = size;
|
||||
segptr->_ds.shm_cpid = cygpid;
|
||||
segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times.
|
||||
|
||||
return segptr->_shmid;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::new_segment ()
|
||||
*
|
||||
* Allocate a new segment for the given key and file map with the
|
||||
* lowest available intid and insert into the segment map.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::segment_t *
|
||||
server_shmmgr::new_segment (const key_t key, const size_t size,
|
||||
const HANDLE hFileMap)
|
||||
{
|
||||
// FIXME: Overflow risk.
|
||||
if (_shm_tot + size > SHMALL)
|
||||
return NULL;
|
||||
|
||||
int intid = 0; // Next expected intid value.
|
||||
segment_t *previous = NULL; // Insert pointer.
|
||||
|
||||
// Find first unallocated intid.
|
||||
for (segment_t *segptr = _segments_head;
|
||||
segptr && segptr->_intid == intid;
|
||||
segptr = segptr->_next, intid++)
|
||||
{
|
||||
previous = segptr;
|
||||
}
|
||||
|
||||
/* By the time this condition is reached (given the default value of
|
||||
* SHMMNI), the linear searches should all replaced by something
|
||||
* just a *little* cleverer . . .
|
||||
*/
|
||||
if (intid >= SHMMNI)
|
||||
return NULL;
|
||||
|
||||
segment_t *const segptr = safe_new (segment_t, key, intid, hFileMap);
|
||||
|
||||
assert (segptr);
|
||||
|
||||
if (previous)
|
||||
{
|
||||
segptr->_next = previous->_next;
|
||||
previous->_next = segptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
segptr->_next = _segments_head;
|
||||
_segments_head = segptr;
|
||||
}
|
||||
|
||||
_shm_ids += 1;
|
||||
_shm_tot += size;
|
||||
if (intid > _intid_max)
|
||||
_intid_max = intid;
|
||||
|
||||
return segptr;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::delete_segment ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
void
|
||||
server_shmmgr::delete_segment (segment_t *const segptr)
|
||||
{
|
||||
assert (segptr);
|
||||
assert (segptr->is_pending_delete ());
|
||||
|
||||
segment_t *previous = NULL;
|
||||
|
||||
const segment_t *const tmp = find (segptr->_intid, &previous);
|
||||
|
||||
assert (tmp == segptr);
|
||||
assert (previous ? previous->_next == segptr : _segments_head == segptr);
|
||||
|
||||
if (previous)
|
||||
previous->_next = segptr->_next;
|
||||
else
|
||||
_segments_head = segptr->_next;
|
||||
|
||||
assert (_shm_ids > 0);
|
||||
_shm_ids -= 1;
|
||||
_shm_tot -= segptr->_ds.shm_segsz;
|
||||
|
||||
safe_delete (segptr);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* client_request_shm::client_request_shm ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
client_request_shm::client_request_shm ()
|
||||
: client_request (CYGSERVER_REQUEST_SHM,
|
||||
&_parameters, sizeof (_parameters))
|
||||
{
|
||||
// verbose: syscall_printf ("created");
|
||||
{
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* client_request_shm::serve ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
void
|
||||
client_request_shm::serve (transport_layer_base *const conn,
|
||||
process_cache *const cache)
|
||||
process_cache *const cache)
|
||||
{
|
||||
assert (conn);
|
||||
|
||||
assert (!error_code ());
|
||||
|
||||
if (msglen () != sizeof (_parameters.in))
|
||||
{
|
||||
syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
|
||||
@@ -837,60 +43,76 @@ client_request_shm::serve (transport_layer_base *const conn,
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Get a return code out of this and don't continue on error.
|
||||
conn->impersonate_client ();
|
||||
|
||||
class process *const client = cache->process (_parameters.in.cygpid,
|
||||
_parameters.in.winpid);
|
||||
|
||||
if (support_sharedmem == TUN_FALSE)
|
||||
{
|
||||
syscall_printf ("Shared memory support not started");
|
||||
error_code (ENOSYS);
|
||||
if (_parameters.in.shmop == SHMOP_shmat)
|
||||
_parameters.out.ptr = (vm_offset_t)0;
|
||||
else
|
||||
_parameters.out.ret = -1;
|
||||
msglen (sizeof (_parameters.out));
|
||||
return;
|
||||
}
|
||||
process *const client = cache->process (_parameters.in.ipcblk.cygpid,
|
||||
_parameters.in.ipcblk.winpid);
|
||||
if (!client)
|
||||
{
|
||||
error_code (EAGAIN);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
|
||||
int result = -EINVAL;
|
||||
|
||||
switch (_parameters.in.shmop)
|
||||
if (!conn->impersonate_client ())
|
||||
{
|
||||
case SHMOP_shmget:
|
||||
result = shmmgr.shmget (_parameters.out.shmid,
|
||||
_parameters.in.key, _parameters.in.size,
|
||||
_parameters.in.shmflg,
|
||||
_parameters.in.uid, _parameters.in.gid,
|
||||
client);
|
||||
break;
|
||||
|
||||
case SHMOP_shmat:
|
||||
result = shmmgr.shmat (_parameters.out.hFileMap,
|
||||
_parameters.in.shmid, _parameters.in.shmflg,
|
||||
client);
|
||||
break;
|
||||
|
||||
case SHMOP_shmdt:
|
||||
result = shmmgr.shmdt (_parameters.in.shmid, client);
|
||||
break;
|
||||
|
||||
case SHMOP_shmctl:
|
||||
result = shmmgr.shmctl (_parameters.out.shmid,
|
||||
_parameters.out.ds, _parameters.out.shminfo,
|
||||
_parameters.out.shm_info,
|
||||
_parameters.in.shmid, _parameters.in.cmd,
|
||||
_parameters.in.ds,
|
||||
client);
|
||||
break;
|
||||
}
|
||||
|
||||
client->release ();
|
||||
conn->revert_to_self ();
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
error_code (-result);
|
||||
client->release ();
|
||||
error_code (EACCES);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
if (!adjust_identity_info (&_parameters.in.ipcblk))
|
||||
{
|
||||
client->release ();
|
||||
conn->revert_to_self ();
|
||||
error_code (EACCES);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
/* Early revert_to_self since IPC code runs in kernel mode. */
|
||||
conn->revert_to_self ();
|
||||
thread td = { client, &_parameters.in.ipcblk, {0, 0} };
|
||||
int res;
|
||||
shmop_t shmop = _parameters.in.shmop; /* Get's overwritten otherwise. */
|
||||
switch (shmop)
|
||||
{
|
||||
case SHMOP_shmat:
|
||||
ipc_p_vmspace (td.ipcblk);
|
||||
res = shmat (&td, &_parameters.in.atargs);
|
||||
break;
|
||||
case SHMOP_shmctl:
|
||||
res = shmctl (&td, &_parameters.in.ctlargs);
|
||||
break;
|
||||
case SHMOP_shmdt:
|
||||
ipc_p_vmspace (td.ipcblk);
|
||||
res = shmdt (&td, &_parameters.in.dtargs);
|
||||
break;
|
||||
case SHMOP_shmget:
|
||||
res = shmget (&td, &_parameters.in.getargs);
|
||||
break;
|
||||
case SHMOP_shmfork:
|
||||
res = cygwin_shmfork_myhook (&td, &_parameters.in.forkargs);
|
||||
break;
|
||||
}
|
||||
/* Allocated by the call to adjust_identity_info(). */
|
||||
if (_parameters.in.ipcblk.gidlist)
|
||||
free (_parameters.in.ipcblk.gidlist);
|
||||
client->release ();
|
||||
error_code (res);
|
||||
if (shmop == SHMOP_shmat)
|
||||
_parameters.out.ptr = td.td_retval[0];
|
||||
else
|
||||
msglen (sizeof (_parameters.out));
|
||||
_parameters.out.ret = td.td_retval[0];
|
||||
if (shmop == SHMOP_shmget)
|
||||
_parameters.out.obj = td.td_retval[1];
|
||||
msglen (sizeof (_parameters.out));
|
||||
}
|
||||
#endif /* __OUTSIDE_CYGWIN__ */
|
||||
|
Reference in New Issue
Block a user