// Copyright (c) 1999-2002 David Muse
// See the COPYING file for more information
#include <rudiments/sharedmemory.h>
#include <rudiments/passwdentry.h>
#include <rudiments/groupentry.h>
#include <rudiments/rawbuffer.h>
#include <rudiments/error.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef RUDIMENTS_NAMESPACE
namespace rudiments {
#endif
class sharedmemoryprivate {
friend class sharedmemory;
private:
int _shmid;
bool _created;
void *_shmptr;
};
sharedmemory::sharedmemory() {
pvt=new sharedmemoryprivate;
pvt->_shmid=-1;
pvt->_created=false;
pvt->_shmptr=NULL;
}
sharedmemory::~sharedmemory() {
if (pvt->_created) {
forceRemove();
}
delete pvt;
}
bool sharedmemory::forceRemove() {
return shmControl(IPC_RMID,NULL);
}
void sharedmemory::dontRemove() {
pvt->_created=false;
}
int sharedmemory::getId() const {
return pvt->_shmid;
}
void *sharedmemory::getPointer() const {
return pvt->_shmptr;
}
bool sharedmemory::setUserId(uid_t uid) {
shmid_ds setds;
setds.shm_perm.uid=uid;
return shmControl(IPC_SET,&setds);
}
bool sharedmemory::setGroupId(gid_t gid) {
shmid_ds setds;
setds.shm_perm.gid=gid;
return shmControl(IPC_SET,&setds);
}
bool sharedmemory::setPermissions(mode_t permissions) {
shmid_ds setds;
setds.shm_perm.mode=permissions;
return shmControl(IPC_SET,&setds);
}
uid_t sharedmemory::getUserId() {
shmid_ds getds;
if (shmControl(IPC_STAT,&getds)) {
return getds.shm_perm.uid;
}
return 0;
}
gid_t sharedmemory::getGroupId() {
shmid_ds getds;
if (shmControl(IPC_STAT,&getds)) {
return getds.shm_perm.gid;
}
return 0;
}
mode_t sharedmemory::getPermissions() {
shmid_ds getds;
if (shmControl(IPC_STAT,&getds)) {
return getds.shm_perm.mode;
}
return 0;
}
bool sharedmemory::create(key_t key, size_t size, mode_t permissions) {
// create the shared memory segment
if ((pvt->_shmid=shmget(key,size,IPC_CREAT|IPC_EXCL|permissions))!=-1) {
// mark for removal
pvt->_created=true;
// attach to the segment, remove the
// segment and return 0 on failure
pvt->_shmptr=shmAttach();
if (reinterpret_cast<long>(pvt->_shmptr)==-1) {
forceRemove();
return false;
}
// init the segment to zero's
rawbuffer::zero(pvt->_shmptr,size);
return true;
}
return false;
}
bool sharedmemory::attach(key_t key) {
// shmat's documentation says something like...
// RETURN VALUE
// On failure shmat returns -1 with errno indicating the error.
// On success shmat returns the address of the attached shared
// memory segment.
// So you might think, ok shmat()>-1 is success. Ahh, but wait, shmat()
// returns a (void *) which doesn't really have an well defined size.
// So, it's possible for a memory address to be much bigger than the
// upper bound of whatever really big, signed integer your system might
// have and thus appear to be a negative number when cast to that type.
// This appears to happen on Solaris x86 all the time. Also, compilers
// don't like it when you compare (void *)'s to numbers, so you have to
// cast it. And you can't just cast it to an unsigned integer because
// it needs to be compared to -1. So, we cast it to a signed integer
// to see if it's not -1, but allow that it could very well be less
// than -1 and still be valid.
return ((pvt->_shmid=shmGet(key,0,0))!=-1 &&
reinterpret_cast<long>(pvt->_shmptr=shmAttach())!=-1);
}
bool sharedmemory::createOrAttach(key_t key, size_t size, mode_t permissions) {
// create the shared memory segment
if ((pvt->_shmid=shmGet(key,size,IPC_CREAT|IPC_EXCL|permissions))!=-1) {
// mark for removal
pvt->_created=true;
// attach to the segment, remove the
// segment and return 0 on failure
pvt->_shmptr=shmAttach();
if (reinterpret_cast<long>(pvt->_shmptr)==-1) {
forceRemove();
return false;
}
// init the segment to zero's
rawbuffer::zero(pvt->_shmptr,size);
return true;
} else if (error::getErrorNumber()==EEXIST &&
(pvt->_shmid=shmGet(key,0,permissions))!=-1) {
// attach to the segment, return 1 on success and 0 on failure
pvt->_shmptr=shmAttach();
return (reinterpret_cast<long>(pvt->_shmptr)!=-1);
}
return false;
}
const char *sharedmemory::getUserName() {
shmid_ds getds;
char *name;
if (shmControl(IPC_STAT,&getds) &&
passwdentry::getName(getds.shm_perm.uid,&name)) {
return name;
}
return NULL;
}
const char *sharedmemory::getGroupName() {
shmid_ds getds;
char *name;
if (shmControl(IPC_STAT,&getds) &&
groupentry::getName(getds.shm_perm.gid,&name)) {
return name;
}
return NULL;
}
bool sharedmemory::setUserName(const char *username) {
uid_t userid;
return (passwdentry::getUserId(username,&userid) &&
setUserId(userid));
}
bool sharedmemory::setGroupName(const char *groupname) {
gid_t groupid;
return (groupentry::getGroupId(groupname,&groupid) &&
setGroupId(groupid));
}
int sharedmemory::shmGet(key_t key, size_t size, int shmflag) {
int result;
do {
result=shmget(key,size,shmflag);
} while (result==-1 && error::getErrorNumber()==EINTR);
return result;
}
void *sharedmemory::shmAttach() {
void *result;
do {
result=shmat(pvt->_shmid,0,0);
} while (reinterpret_cast<long>(result)==-1 &&
error::getErrorNumber()==EINTR);
return result;
}
bool sharedmemory::shmControl(int cmd, shmid_ds *buf) {
int result;
do {
result=shmctl(pvt->_shmid,cmd,buf);
} while (result==-1 && error::getErrorNumber()==EINTR);
return !result;
}
#ifdef RUDIMENTS_NAMESPACE
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1