summaryrefslogtreecommitdiff
path: root/Xext/shm.c
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2013-01-17 13:46:55 -0800
committerKeith Packard <keithp@keithp.com>2013-10-31 16:58:28 -0700
commitfdec793cdc2ef9a6ea66b311cb1068a7bd4a3be3 (patch)
treefb668e21ad877c1719181d672836806bcff318fe /Xext/shm.c
parent9fd35daa3160fd36f00ed354bfcbefefa1353cce (diff)
Add support for MIT-SHM AttachFd request
This passes a file descriptor from the client to the server, which is then mmap'd Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Adam Jackson <ajax@redhat.com>
Diffstat (limited to 'Xext/shm.c')
-rw-r--r--Xext/shm.c159
1 files changed, 156 insertions, 3 deletions
diff --git a/Xext/shm.c b/Xext/shm.c
index f6995ccfb..1a70260fb 100644
--- a/Xext/shm.c
+++ b/Xext/shm.c
@@ -53,6 +53,7 @@ in this Software without prior written authorization from The Open Group.
#include "xace.h"
#include <X11/extensions/shmproto.h>
#include <X11/Xfuncproto.h>
+#include <sys/mman.h>
#include "protocol-versions.h"
/* Needed for Solaris cross-zone shared memory extension */
@@ -382,8 +383,10 @@ ProcShmAttach(ClientPtr client)
client->errorValue = stuff->readOnly;
return BadValue;
}
- for (shmdesc = Shmsegs;
- shmdesc && (shmdesc->shmid != stuff->shmid); shmdesc = shmdesc->next);
+ for (shmdesc = Shmsegs; shmdesc; shmdesc = shmdesc->next) {
+ if (!shmdesc->is_fd && shmdesc->shmid == stuff->shmid)
+ break;
+ }
if (shmdesc) {
if (!stuff->readOnly && !shmdesc->writable)
return BadAccess;
@@ -393,6 +396,7 @@ ProcShmAttach(ClientPtr client)
shmdesc = malloc(sizeof(ShmDescRec));
if (!shmdesc)
return BadAlloc;
+ shmdesc->is_fd = FALSE;
shmdesc->addr = shmat(stuff->shmid, 0,
stuff->readOnly ? SHM_RDONLY : 0);
if ((shmdesc->addr == ((char *) -1)) || SHMSTAT(stuff->shmid, &buf)) {
@@ -431,7 +435,10 @@ ShmDetachSegment(pointer value, /* must conform to DeleteType */
if (--shmdesc->refcnt)
return TRUE;
- shmdt(shmdesc->addr);
+ if (shmdesc->is_fd)
+ munmap(shmdesc->addr, shmdesc->size);
+ else
+ shmdt(shmdesc->addr);
for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next);
*prev = shmdesc->next;
free(shmdesc);
@@ -1088,6 +1095,122 @@ ProcShmCreatePixmap(ClientPtr client)
}
static int
+ProcShmAttachFd(ClientPtr client)
+{
+ int fd;
+ ShmDescPtr shmdesc;
+ REQUEST(xShmAttachFdReq);
+ struct stat statb;
+
+ SetReqFds(client, 1);
+ REQUEST_SIZE_MATCH(xShmAttachFdReq);
+ LEGAL_NEW_RESOURCE(stuff->shmseg, client);
+ if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
+ client->errorValue = stuff->readOnly;
+ return BadValue;
+ }
+ fd = ReadFdFromClient(client);
+ if (fd < 0)
+ return BadMatch;
+
+ if (fstat(fd, &statb) < 0 || statb.st_size == 0) {
+ close(fd);
+ return BadMatch;
+ }
+
+ shmdesc = malloc(sizeof(ShmDescRec));
+ if (!shmdesc) {
+ close(fd);
+ return BadAlloc;
+ }
+ shmdesc->is_fd = TRUE;
+ shmdesc->addr = mmap(NULL, statb.st_size,
+ stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
+ MAP_SHARED,
+ fd, 0);
+
+ close(fd);
+ if ((shmdesc->addr == ((char *) -1))) {
+ free(shmdesc);
+ return BadAccess;
+ }
+
+ shmdesc->refcnt = 1;
+ shmdesc->writable = !stuff->readOnly;
+ shmdesc->size = statb.st_size;
+ shmdesc->next = Shmsegs;
+ Shmsegs = shmdesc;
+
+ if (!AddResource(stuff->shmseg, ShmSegType, (pointer) shmdesc))
+ return BadAlloc;
+ return Success;
+}
+
+static int
+ProcShmCreateSegment(ClientPtr client)
+{
+ int fd;
+ ShmDescPtr shmdesc;
+ REQUEST(xShmCreateSegmentReq);
+ xShmCreateSegmentReply rep = {
+ .type = X_Reply,
+ .nfd = 1,
+ .sequenceNumber = client->sequence,
+ .length = 0,
+ };
+ char template[] = "/tmp/shm-XXXXXX";
+
+ REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
+ if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
+ client->errorValue = stuff->readOnly;
+ return BadValue;
+ }
+ fd = mkstemp(template);
+ if (fd < 0)
+ return BadAlloc;
+ unlink(template);
+ if (ftruncate(fd, stuff->size) < 0) {
+ close(fd);
+ return BadAlloc;
+ }
+ shmdesc = malloc(sizeof(ShmDescRec));
+ if (!shmdesc) {
+ close(fd);
+ return BadAlloc;
+ }
+ shmdesc->is_fd = TRUE;
+ shmdesc->addr = mmap(NULL, stuff->size,
+ stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
+ MAP_SHARED,
+ fd, 0);
+
+ if ((shmdesc->addr == ((char *) -1))) {
+ close(fd);
+ free(shmdesc);
+ return BadAccess;
+ }
+
+ shmdesc->refcnt = 1;
+ shmdesc->writable = !stuff->readOnly;
+ shmdesc->size = stuff->size;
+ shmdesc->next = Shmsegs;
+ Shmsegs = shmdesc;
+
+ if (!AddResource(stuff->shmseg, ShmSegType, (pointer) shmdesc)) {
+ close(fd);
+ return BadAlloc;
+ }
+
+ if (WriteFdToClient(client, fd, TRUE) < 0) {
+ FreeResource(stuff->shmseg, RT_NONE);
+ close(fd);
+ return BadAlloc;
+ }
+ WriteToClient(client, sizeof (xShmCreateSegmentReply), &rep);
+ return Success;
+}
+
+static int
ProcShmDispatch(ClientPtr client)
{
REQUEST(xReq);
@@ -1116,6 +1239,10 @@ ProcShmDispatch(ClientPtr client)
return ProcPanoramiXShmCreatePixmap(client);
#endif
return ProcShmCreatePixmap(client);
+ case X_ShmAttachFd:
+ return ProcShmAttachFd(client);
+ case X_ShmCreateSegment:
+ return ProcShmCreateSegment(client);
default:
return BadRequest;
}
@@ -1217,6 +1344,28 @@ SProcShmCreatePixmap(ClientPtr client)
}
static int
+SProcShmAttachFd(ClientPtr client)
+{
+ REQUEST(xShmAttachFdReq);
+ SetReqFds(client, 1);
+ swaps(&stuff->length);
+ REQUEST_SIZE_MATCH(xShmAttachFdReq);
+ swapl(&stuff->shmseg);
+ return ProcShmAttachFd(client);
+}
+
+static int
+SProcShmCreateSegment(ClientPtr client)
+{
+ REQUEST(xShmCreateSegmentReq);
+ swaps(&stuff->length);
+ REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
+ swapl(&stuff->shmseg);
+ swapl(&stuff->size);
+ return ProcShmCreateSegment(client);
+}
+
+static int
SProcShmDispatch(ClientPtr client)
{
REQUEST(xReq);
@@ -1233,6 +1382,10 @@ SProcShmDispatch(ClientPtr client)
return SProcShmGetImage(client);
case X_ShmCreatePixmap:
return SProcShmCreatePixmap(client);
+ case X_ShmAttachFd:
+ return SProcShmAttachFd(client);
+ case X_ShmCreateSegment:
+ return SProcShmCreateSegment(client);
default:
return BadRequest;
}