xwayland/glamor: Disable GLAMOR after GBM cleanup
[xserver.git] / Xext / shm.c
blob5d07f30f167b0f2b5dea69396ac9ac873c3dc533
1 /************************************************************
3 Copyright 1989, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
25 ********************************************************/
27 /* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */
29 #define SHM
31 #include <dix-config.h>
33 #include <sys/types.h>
34 #include <sys/ipc.h>
35 #include <sys/shm.h>
36 #include <sys/mman.h>
37 #include <unistd.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <X11/X.h>
41 #include <X11/Xproto.h>
42 #include <X11/extensions/shmproto.h>
43 #include <X11/Xfuncproto.h>
45 #include "dix/dix_priv.h"
46 #include "os/auth.h"
47 #include "os/busfault.h"
48 #include "os/osdep.h"
50 #include "misc.h"
51 #include "os.h"
52 #include "dixstruct_priv.h"
53 #include "resource.h"
54 #include "scrnintstr.h"
55 #include "windowstr.h"
56 #include "pixmapstr.h"
57 #include "gcstruct.h"
58 #include "extnsionst.h"
59 #include "servermd.h"
60 #include "shmint.h"
61 #include "xace.h"
62 #include "extinit_priv.h"
63 #include "protocol-versions.h"
65 /* Needed for Solaris cross-zone shared memory extension */
66 #ifdef HAVE_SHMCTL64
67 #include <sys/ipc_impl.h>
68 #define SHMSTAT(id, buf) shmctl64(id, IPC_STAT64, buf)
69 #define SHMSTAT_TYPE struct shmid_ds64
70 #define SHMPERM_TYPE struct ipc_perm64
71 #define SHM_PERM(buf) buf.shmx_perm
72 #define SHM_SEGSZ(buf) buf.shmx_segsz
73 #define SHMPERM_UID(p) p->ipcx_uid
74 #define SHMPERM_CUID(p) p->ipcx_cuid
75 #define SHMPERM_GID(p) p->ipcx_gid
76 #define SHMPERM_CGID(p) p->ipcx_cgid
77 #define SHMPERM_MODE(p) p->ipcx_mode
78 #define SHMPERM_ZONEID(p) p->ipcx_zoneid
79 #else
80 #define SHMSTAT(id, buf) shmctl(id, IPC_STAT, buf)
81 #define SHMSTAT_TYPE struct shmid_ds
82 #define SHMPERM_TYPE struct ipc_perm
83 #define SHM_PERM(buf) buf.shm_perm
84 #define SHM_SEGSZ(buf) buf.shm_segsz
85 #define SHMPERM_UID(p) p->uid
86 #define SHMPERM_CUID(p) p->cuid
87 #define SHMPERM_GID(p) p->gid
88 #define SHMPERM_CGID(p) p->cgid
89 #define SHMPERM_MODE(p) p->mode
90 #endif
92 #ifdef PANORAMIX
93 #include "panoramiX.h"
94 #include "panoramiXsrv.h"
95 #endif
97 typedef struct _ShmScrPrivateRec {
98 CloseScreenProcPtr CloseScreen;
99 ShmFuncsPtr shmFuncs;
100 DestroyPixmapProcPtr destroyPixmap;
101 } ShmScrPrivateRec;
103 static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS);
104 static int ShmDetachSegment(void *value, XID shmseg);
105 static void ShmResetProc(ExtensionEntry *extEntry);
106 static void SShmCompletionEvent(xShmCompletionEvent *from,
107 xShmCompletionEvent *to);
109 static Bool ShmDestroyPixmap(PixmapPtr pPixmap);
111 static unsigned char ShmReqCode;
112 int ShmCompletionCode;
113 int BadShmSegCode;
114 RESTYPE ShmSegType;
115 static ShmDescPtr Shmsegs;
116 static Bool sharedPixmaps;
117 static DevPrivateKeyRec shmScrPrivateKeyRec;
119 #define shmScrPrivateKey (&shmScrPrivateKeyRec)
120 static DevPrivateKeyRec shmPixmapPrivateKeyRec;
122 #define shmPixmapPrivateKey (&shmPixmapPrivateKeyRec)
123 static ShmFuncs miFuncs = { NULL, NULL };
124 static ShmFuncs fbFuncs = { fbShmCreatePixmap, NULL };
126 #define ShmGetScreenPriv(s) ((ShmScrPrivateRec *)dixLookupPrivate(&(s)->devPrivates, shmScrPrivateKey))
128 #define VERIFY_SHMSEG(shmseg,shmdesc,client) \
130 int tmprc; \
131 tmprc = dixLookupResourceByType((void **)&(shmdesc), shmseg, ShmSegType, \
132 client, DixReadAccess); \
133 if (tmprc != Success) \
134 return tmprc; \
137 #define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \
139 VERIFY_SHMSEG(shmseg, shmdesc, client); \
140 if ((offset & 3) || (offset > shmdesc->size)) \
142 client->errorValue = offset; \
143 return BadValue; \
145 if (needwrite && !shmdesc->writable) \
146 return BadAccess; \
149 #define VERIFY_SHMSIZE(shmdesc,offset,len,client) \
151 if ((offset + len) > shmdesc->size) \
153 return BadAccess; \
157 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
159 static Bool badSysCall = FALSE;
161 static void
162 SigSysHandler(int signo)
164 badSysCall = TRUE;
167 static Bool
168 CheckForShmSyscall(void)
170 void (*oldHandler) (int);
171 int shmid = -1;
173 /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
174 oldHandler = OsSignal(SIGSYS, SigSysHandler);
176 badSysCall = FALSE;
177 shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
179 if (shmid != -1) {
180 /* Successful allocation - clean up */
181 shmctl(shmid, IPC_RMID, NULL);
183 else {
184 /* Allocation failed */
185 badSysCall = TRUE;
187 OsSignal(SIGSYS, oldHandler);
188 return !badSysCall;
191 #define MUST_CHECK_FOR_SHM_SYSCALL
193 #endif
195 static Bool
196 ShmCloseScreen(ScreenPtr pScreen)
198 ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
200 pScreen->CloseScreen = screen_priv->CloseScreen;
201 dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL);
202 free(screen_priv);
203 return (*pScreen->CloseScreen) (pScreen);
206 static ShmScrPrivateRec *
207 ShmInitScreenPriv(ScreenPtr pScreen)
209 ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
211 if (!screen_priv) {
212 screen_priv = calloc(1, sizeof(ShmScrPrivateRec));
213 screen_priv->CloseScreen = pScreen->CloseScreen;
214 dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv);
215 pScreen->CloseScreen = ShmCloseScreen;
217 return screen_priv;
220 static Bool
221 ShmRegisterPrivates(void)
223 if (!dixRegisterPrivateKey(&shmScrPrivateKeyRec, PRIVATE_SCREEN, 0))
224 return FALSE;
225 if (!dixRegisterPrivateKey(&shmPixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
226 return FALSE;
227 return TRUE;
230 /*ARGSUSED*/ static void
231 ShmResetProc(ExtensionEntry * extEntry)
233 int i;
235 for (i = 0; i < screenInfo.numScreens; i++)
236 ShmRegisterFuncs(screenInfo.screens[i], NULL);
239 void
240 ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs)
242 if (!ShmRegisterPrivates())
243 return;
244 ShmInitScreenPriv(pScreen)->shmFuncs = funcs;
247 static Bool
248 ShmDestroyPixmap(PixmapPtr pPixmap)
250 ScreenPtr pScreen = pPixmap->drawable.pScreen;
251 ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
252 void *shmdesc = NULL;
253 Bool ret;
255 if (pPixmap->refcnt == 1)
256 shmdesc = dixLookupPrivate(&pPixmap->devPrivates, shmPixmapPrivateKey);
258 pScreen->DestroyPixmap = screen_priv->destroyPixmap;
259 ret = (*pScreen->DestroyPixmap) (pPixmap);
260 screen_priv->destroyPixmap = pScreen->DestroyPixmap;
261 pScreen->DestroyPixmap = ShmDestroyPixmap;
263 if (shmdesc)
264 ShmDetachSegment(shmdesc, 0);
266 return ret;
269 void
270 ShmRegisterFbFuncs(ScreenPtr pScreen)
272 ShmRegisterFuncs(pScreen, &fbFuncs);
275 static int
276 ProcShmQueryVersion(ClientPtr client)
278 xShmQueryVersionReply rep = {
279 .type = X_Reply,
280 .sharedPixmaps = sharedPixmaps,
281 .sequenceNumber = client->sequence,
282 .length = 0,
283 .majorVersion = SERVER_SHM_MAJOR_VERSION,
284 .minorVersion = SERVER_SHM_MINOR_VERSION,
285 .uid = geteuid(),
286 .gid = getegid(),
287 .pixmapFormat = sharedPixmaps ? ZPixmap : 0
290 REQUEST_SIZE_MATCH(xShmQueryVersionReq);
292 if (client->swapped) {
293 swaps(&rep.sequenceNumber);
294 swapl(&rep.length);
295 swaps(&rep.majorVersion);
296 swaps(&rep.minorVersion);
297 swaps(&rep.uid);
298 swaps(&rep.gid);
300 WriteToClient(client, sizeof(xShmQueryVersionReply), &rep);
301 return Success;
305 * Simulate the access() system call for a shared memory segment,
306 * using the credentials from the client if available.
308 static int
309 shm_access(ClientPtr client, SHMPERM_TYPE * perm, int readonly)
311 int uid, gid;
312 mode_t mask;
313 int uidset = 0, gidset = 0;
314 LocalClientCredRec *lcc;
316 if (GetLocalClientCreds(client, &lcc) != -1) {
318 if (lcc->fieldsSet & LCC_UID_SET) {
319 uid = lcc->euid;
320 uidset = 1;
322 if (lcc->fieldsSet & LCC_GID_SET) {
323 gid = lcc->egid;
324 gidset = 1;
327 #if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID)
328 if (((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1)
329 || (lcc->zoneid != SHMPERM_ZONEID(perm))) {
330 uidset = 0;
331 gidset = 0;
333 #endif
334 FreeLocalClientCreds(lcc);
336 if (uidset) {
337 /* User id 0 always gets access */
338 if (uid == 0) {
339 return 0;
341 /* Check the owner */
342 if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) {
343 mask = S_IRUSR;
344 if (!readonly) {
345 mask |= S_IWUSR;
347 return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
351 if (gidset) {
352 /* Check the group */
353 if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) {
354 mask = S_IRGRP;
355 if (!readonly) {
356 mask |= S_IWGRP;
358 return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
362 /* Otherwise, check everyone else */
363 mask = S_IROTH;
364 if (!readonly) {
365 mask |= S_IWOTH;
367 return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
370 static int
371 ProcShmAttach(ClientPtr client)
373 SHMSTAT_TYPE buf;
374 ShmDescPtr shmdesc;
376 REQUEST(xShmAttachReq);
378 REQUEST_SIZE_MATCH(xShmAttachReq);
379 LEGAL_NEW_RESOURCE(stuff->shmseg, client);
380 if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
381 client->errorValue = stuff->readOnly;
382 return BadValue;
384 for (shmdesc = Shmsegs; shmdesc; shmdesc = shmdesc->next) {
385 if (!SHMDESC_IS_FD(shmdesc) && shmdesc->shmid == stuff->shmid)
386 break;
388 if (shmdesc) {
389 if (!stuff->readOnly && !shmdesc->writable)
390 return BadAccess;
391 shmdesc->refcnt++;
393 else {
394 shmdesc = malloc(sizeof(ShmDescRec));
395 if (!shmdesc)
396 return BadAlloc;
397 #ifdef SHM_FD_PASSING
398 shmdesc->is_fd = FALSE;
399 #endif
400 shmdesc->addr = shmat(stuff->shmid, 0,
401 stuff->readOnly ? SHM_RDONLY : 0);
402 if ((shmdesc->addr == ((char *) -1)) || SHMSTAT(stuff->shmid, &buf)) {
403 free(shmdesc);
404 return BadAccess;
407 /* The attach was performed with root privs. We must
408 * do manual checking of access rights for the credentials
409 * of the client */
411 if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) {
412 shmdt(shmdesc->addr);
413 free(shmdesc);
414 return BadAccess;
417 shmdesc->shmid = stuff->shmid;
418 shmdesc->refcnt = 1;
419 shmdesc->writable = !stuff->readOnly;
420 shmdesc->size = SHM_SEGSZ(buf);
421 shmdesc->next = Shmsegs;
422 Shmsegs = shmdesc;
424 if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
425 return BadAlloc;
426 return Success;
429 /*ARGSUSED*/ static int
430 ShmDetachSegment(void *value, /* must conform to DeleteType */
431 XID unused)
433 ShmDescPtr shmdesc = (ShmDescPtr) value;
434 ShmDescPtr *prev;
436 if (--shmdesc->refcnt)
437 return TRUE;
438 #if SHM_FD_PASSING
439 if (shmdesc->is_fd) {
440 if (shmdesc->busfault)
441 busfault_unregister(shmdesc->busfault);
442 munmap(shmdesc->addr, shmdesc->size);
443 } else
444 #endif
445 shmdt(shmdesc->addr);
446 for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next);
447 *prev = shmdesc->next;
448 free(shmdesc);
449 return Success;
452 static int
453 ProcShmDetach(ClientPtr client)
455 ShmDescPtr shmdesc;
457 REQUEST(xShmDetachReq);
459 REQUEST_SIZE_MATCH(xShmDetachReq);
460 VERIFY_SHMSEG(stuff->shmseg, shmdesc, client);
461 FreeResource(stuff->shmseg, X11_RESTYPE_NONE);
462 return Success;
466 * If the given request doesn't exactly match PutImage's constraints,
467 * wrap the image in a scratch pixmap header and let CopyArea sort it out.
469 static void
470 doShmPutImage(DrawablePtr dst, GCPtr pGC,
471 int depth, unsigned int format,
472 int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
473 char *data)
475 PixmapPtr pPixmap;
477 if (format == ZPixmap || (format == XYPixmap && depth == 1)) {
478 pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth,
479 BitsPerPixel(depth),
480 PixmapBytePad(w, depth), data);
481 if (!pPixmap)
482 return;
483 (void) pGC->ops->CopyArea((DrawablePtr) pPixmap, dst, pGC,
484 sx, sy, sw, sh, dx, dy);
485 FreeScratchPixmapHeader(pPixmap);
487 else {
488 GCPtr putGC = GetScratchGC(depth, dst->pScreen);
490 if (!putGC)
491 return;
493 pPixmap = (*dst->pScreen->CreatePixmap) (dst->pScreen, sw, sh, depth,
494 CREATE_PIXMAP_USAGE_SCRATCH);
495 if (!pPixmap) {
496 FreeScratchGC(putGC);
497 return;
499 ValidateGC(&pPixmap->drawable, putGC);
500 (*putGC->ops->PutImage) (&pPixmap->drawable, putGC, depth, -sx, -sy, w,
501 h, 0,
502 (format == XYPixmap) ? XYPixmap : ZPixmap,
503 data);
504 FreeScratchGC(putGC);
505 if (format == XYBitmap)
506 (void) (*pGC->ops->CopyPlane) (&pPixmap->drawable, dst, pGC, 0, 0,
507 sw, sh, dx, dy, 1L);
508 else
509 (void) (*pGC->ops->CopyArea) (&pPixmap->drawable, dst, pGC, 0, 0,
510 sw, sh, dx, dy);
511 (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap);
515 static int
516 ProcShmPutImage(ClientPtr client)
518 GCPtr pGC;
519 DrawablePtr pDraw;
520 long length;
521 ShmDescPtr shmdesc;
523 REQUEST(xShmPutImageReq);
525 REQUEST_SIZE_MATCH(xShmPutImageReq);
526 VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
527 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client);
528 if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse))
529 return BadValue;
530 if (stuff->format == XYBitmap) {
531 if (stuff->depth != 1)
532 return BadMatch;
533 length = PixmapBytePad(stuff->totalWidth, 1);
535 else if (stuff->format == XYPixmap) {
536 if (pDraw->depth != stuff->depth)
537 return BadMatch;
538 length = PixmapBytePad(stuff->totalWidth, 1);
539 length *= stuff->depth;
541 else if (stuff->format == ZPixmap) {
542 if (pDraw->depth != stuff->depth)
543 return BadMatch;
544 length = PixmapBytePad(stuff->totalWidth, stuff->depth);
546 else {
547 client->errorValue = stuff->format;
548 return BadValue;
552 * There's a potential integer overflow in this check:
553 * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight,
554 * client);
555 * the version below ought to avoid it
557 if (stuff->totalHeight != 0 &&
558 length > (shmdesc->size - stuff->offset) / stuff->totalHeight) {
559 client->errorValue = stuff->totalWidth;
560 return BadValue;
562 if (stuff->srcX > stuff->totalWidth) {
563 client->errorValue = stuff->srcX;
564 return BadValue;
566 if (stuff->srcY > stuff->totalHeight) {
567 client->errorValue = stuff->srcY;
568 return BadValue;
570 if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) {
571 client->errorValue = stuff->srcWidth;
572 return BadValue;
574 if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) {
575 client->errorValue = stuff->srcHeight;
576 return BadValue;
579 if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) ||
580 ((stuff->format != ZPixmap) &&
581 (stuff->srcX < screenInfo.bitmapScanlinePad) &&
582 ((stuff->format == XYBitmap) ||
583 ((stuff->srcY == 0) &&
584 (stuff->srcHeight == stuff->totalHeight))))) &&
585 ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth))
586 (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth,
587 stuff->dstX, stuff->dstY,
588 stuff->totalWidth, stuff->srcHeight,
589 stuff->srcX, stuff->format,
590 shmdesc->addr + stuff->offset +
591 (stuff->srcY * length));
592 else
593 doShmPutImage(pDraw, pGC, stuff->depth, stuff->format,
594 stuff->totalWidth, stuff->totalHeight,
595 stuff->srcX, stuff->srcY,
596 stuff->srcWidth, stuff->srcHeight,
597 stuff->dstX, stuff->dstY, shmdesc->addr + stuff->offset);
599 if (stuff->sendEvent) {
600 xShmCompletionEvent ev = {
601 .type = ShmCompletionCode,
602 .drawable = stuff->drawable,
603 .minorEvent = X_ShmPutImage,
604 .majorEvent = ShmReqCode,
605 .shmseg = stuff->shmseg,
606 .offset = stuff->offset
608 WriteEventsToClient(client, 1, (xEvent *) &ev);
611 return Success;
614 static int
615 ProcShmGetImage(ClientPtr client)
617 DrawablePtr pDraw;
618 long lenPer = 0, length;
619 Mask plane = 0;
620 xShmGetImageReply xgi;
621 ShmDescPtr shmdesc;
622 VisualID visual = None;
623 RegionPtr pVisibleRegion = NULL;
624 int rc;
626 REQUEST(xShmGetImageReq);
628 REQUEST_SIZE_MATCH(xShmGetImageReq);
629 if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
630 client->errorValue = stuff->format;
631 return BadValue;
633 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
634 if (rc != Success)
635 return rc;
636 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
637 if (pDraw->type == DRAWABLE_WINDOW) {
638 if ( /* check for being viewable */
639 !((WindowPtr) pDraw)->realized ||
640 /* check for being on screen */
641 pDraw->x + stuff->x < 0 ||
642 pDraw->x + stuff->x + (int) stuff->width > pDraw->pScreen->width
643 || pDraw->y + stuff->y < 0 ||
644 pDraw->y + stuff->y + (int) stuff->height >
645 pDraw->pScreen->height ||
646 /* check for being inside of border */
647 stuff->x < -wBorderWidth((WindowPtr) pDraw) ||
648 stuff->x + (int) stuff->width >
649 wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
650 stuff->y < -wBorderWidth((WindowPtr) pDraw) ||
651 stuff->y + (int) stuff->height >
652 wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
653 return BadMatch;
654 visual = wVisual(((WindowPtr) pDraw));
655 if (pDraw->type == DRAWABLE_WINDOW)
656 pVisibleRegion = &((WindowPtr) pDraw)->borderClip;
657 pDraw->pScreen->SourceValidate(pDraw, stuff->x, stuff->y,
658 stuff->width, stuff->height,
659 IncludeInferiors);
661 else {
662 if (stuff->x < 0 ||
663 stuff->x + (int) stuff->width > pDraw->width ||
664 stuff->y < 0 || stuff->y + (int) stuff->height > pDraw->height)
665 return BadMatch;
666 visual = None;
668 xgi = (xShmGetImageReply) {
669 .type = X_Reply,
670 .sequenceNumber = client->sequence,
671 .length = 0,
672 .visual = visual,
673 .depth = pDraw->depth
675 if (stuff->format == ZPixmap) {
676 length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height;
678 else {
679 lenPer = PixmapBytePad(stuff->width, 1) * stuff->height;
680 plane = ((Mask) 1) << (pDraw->depth - 1);
681 /* only planes asked for */
682 length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
685 VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
686 xgi.size = length;
688 if (length == 0) {
689 /* nothing to do */
691 else if (stuff->format == ZPixmap) {
692 (*pDraw->pScreen->GetImage) (pDraw, stuff->x, stuff->y,
693 stuff->width, stuff->height,
694 stuff->format, stuff->planeMask,
695 shmdesc->addr + stuff->offset);
696 if (pVisibleRegion)
697 XaceCensorImage(client, pVisibleRegion,
698 PixmapBytePad(stuff->width, pDraw->depth), pDraw,
699 stuff->x, stuff->y, stuff->width, stuff->height,
700 stuff->format, shmdesc->addr + stuff->offset);
702 else {
704 length = stuff->offset;
705 for (; plane; plane >>= 1) {
706 if (stuff->planeMask & plane) {
707 (*pDraw->pScreen->GetImage) (pDraw,
708 stuff->x, stuff->y,
709 stuff->width, stuff->height,
710 stuff->format, plane,
711 shmdesc->addr + length);
712 if (pVisibleRegion)
713 XaceCensorImage(client, pVisibleRegion,
714 BitmapBytePad(stuff->width), pDraw,
715 stuff->x, stuff->y, stuff->width, stuff->height,
716 stuff->format, shmdesc->addr + length);
717 length += lenPer;
722 if (client->swapped) {
723 swaps(&xgi.sequenceNumber);
724 swapl(&xgi.length);
725 swapl(&xgi.visual);
726 swapl(&xgi.size);
728 WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
730 return Success;
733 #ifdef PANORAMIX
734 static int
735 ProcPanoramiXShmPutImage(ClientPtr client)
737 int j, result, orig_x, orig_y;
738 PanoramiXRes *draw, *gc;
739 Bool sendEvent, isRoot;
741 REQUEST(xShmPutImageReq);
742 REQUEST_SIZE_MATCH(xShmPutImageReq);
744 result = dixLookupResourceByClass((void **) &draw, stuff->drawable,
745 XRC_DRAWABLE, client, DixWriteAccess);
746 if (result != Success)
747 return (result == BadValue) ? BadDrawable : result;
749 result = dixLookupResourceByType((void **) &gc, stuff->gc,
750 XRT_GC, client, DixReadAccess);
751 if (result != Success)
752 return result;
754 isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
756 orig_x = stuff->dstX;
757 orig_y = stuff->dstY;
758 sendEvent = stuff->sendEvent;
759 stuff->sendEvent = 0;
760 FOR_NSCREENS(j) {
761 if (!j)
762 stuff->sendEvent = sendEvent;
763 stuff->drawable = draw->info[j].id;
764 stuff->gc = gc->info[j].id;
765 if (isRoot) {
766 stuff->dstX = orig_x - screenInfo.screens[j]->x;
767 stuff->dstY = orig_y - screenInfo.screens[j]->y;
769 result = ProcShmPutImage(client);
770 if (result != Success)
771 break;
773 return result;
776 static int
777 ProcPanoramiXShmGetImage(ClientPtr client)
779 PanoramiXRes *draw;
780 DrawablePtr *drawables;
781 DrawablePtr pDraw;
782 xShmGetImageReply xgi;
783 ShmDescPtr shmdesc;
784 int i, x, y, w, h, format, rc;
785 Mask plane = 0, planemask;
786 long lenPer = 0, length, widthBytesLine;
787 Bool isRoot;
789 REQUEST(xShmGetImageReq);
791 REQUEST_SIZE_MATCH(xShmGetImageReq);
793 if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
794 client->errorValue = stuff->format;
795 return BadValue;
798 rc = dixLookupResourceByClass((void **) &draw, stuff->drawable,
799 XRC_DRAWABLE, client, DixWriteAccess);
800 if (rc != Success)
801 return (rc == BadValue) ? BadDrawable : rc;
803 if (draw->type == XRT_PIXMAP)
804 return ProcShmGetImage(client);
806 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
807 if (rc != Success)
808 return rc;
810 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
812 x = stuff->x;
813 y = stuff->y;
814 w = stuff->width;
815 h = stuff->height;
816 format = stuff->format;
817 planemask = stuff->planeMask;
819 isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
821 if (isRoot) {
822 if ( /* check for being onscreen */
823 x < 0 || x + w > PanoramiXPixWidth ||
824 y < 0 || y + h > PanoramiXPixHeight)
825 return BadMatch;
827 else {
828 if ( /* check for being onscreen */
829 screenInfo.screens[0]->x + pDraw->x + x < 0 ||
830 screenInfo.screens[0]->x + pDraw->x + x + w > PanoramiXPixWidth
831 || screenInfo.screens[0]->y + pDraw->y + y < 0 ||
832 screenInfo.screens[0]->y + pDraw->y + y + h > PanoramiXPixHeight
834 /* check for being inside of border */
835 x < -wBorderWidth((WindowPtr) pDraw) ||
836 x + w > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
837 y < -wBorderWidth((WindowPtr) pDraw) ||
838 y + h > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
839 return BadMatch;
842 if (format == ZPixmap) {
843 widthBytesLine = PixmapBytePad(w, pDraw->depth);
844 length = widthBytesLine * h;
846 else {
847 widthBytesLine = PixmapBytePad(w, 1);
848 lenPer = widthBytesLine * h;
849 plane = ((Mask) 1) << (pDraw->depth - 1);
850 length = lenPer * Ones(planemask & (plane | (plane - 1)));
853 VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
855 drawables = calloc(PanoramiXNumScreens, sizeof(DrawablePtr));
856 if (!drawables)
857 return BadAlloc;
859 drawables[0] = pDraw;
860 FOR_NSCREENS_FORWARD_SKIP(i) {
861 rc = dixLookupDrawable(drawables + i, draw->info[i].id, client, 0,
862 DixReadAccess);
863 if (rc != Success) {
864 free(drawables);
865 return rc;
868 FOR_NSCREENS_FORWARD(i) {
869 drawables[i]->pScreen->SourceValidate(drawables[i], 0, 0,
870 drawables[i]->width,
871 drawables[i]->height,
872 IncludeInferiors);
875 xgi = (xShmGetImageReply) {
876 .type = X_Reply,
877 .sequenceNumber = client->sequence,
878 .length = 0,
879 .visual = wVisual(((WindowPtr) pDraw)),
880 .depth = pDraw->depth
883 xgi.size = length;
885 if (length == 0) { /* nothing to do */
887 else if (format == ZPixmap) {
888 XineramaGetImageData(drawables, x, y, w, h, format, planemask,
889 shmdesc->addr + stuff->offset,
890 widthBytesLine, isRoot);
892 else {
894 length = stuff->offset;
895 for (; plane; plane >>= 1) {
896 if (planemask & plane) {
897 XineramaGetImageData(drawables, x, y, w, h,
898 format, plane, shmdesc->addr + length,
899 widthBytesLine, isRoot);
900 length += lenPer;
904 free(drawables);
906 if (client->swapped) {
907 swaps(&xgi.sequenceNumber);
908 swapl(&xgi.length);
909 swapl(&xgi.visual);
910 swapl(&xgi.size);
912 WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
914 return Success;
917 static int
918 ProcPanoramiXShmCreatePixmap(ClientPtr client)
920 ScreenPtr pScreen = NULL;
921 PixmapPtr pMap = NULL;
922 DrawablePtr pDraw;
923 DepthPtr pDepth;
924 int i, j, result, rc;
925 ShmDescPtr shmdesc;
927 REQUEST(xShmCreatePixmapReq);
928 unsigned int width, height, depth;
929 unsigned long size;
930 PanoramiXRes *newPix;
932 REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
933 client->errorValue = stuff->pid;
934 if (!sharedPixmaps)
935 return BadImplementation;
936 LEGAL_NEW_RESOURCE(stuff->pid, client);
937 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
938 DixGetAttrAccess);
939 if (rc != Success)
940 return rc;
942 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
944 width = stuff->width;
945 height = stuff->height;
946 depth = stuff->depth;
947 if (!width || !height || !depth) {
948 client->errorValue = 0;
949 return BadValue;
951 if (width > 32767 || height > 32767)
952 return BadAlloc;
954 if (stuff->depth != 1) {
955 pDepth = pDraw->pScreen->allowedDepths;
956 for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
957 if (pDepth->depth == stuff->depth)
958 goto CreatePmap;
959 client->errorValue = stuff->depth;
960 return BadValue;
963 CreatePmap:
964 size = PixmapBytePad(width, depth) * height;
965 if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
966 if (size < width * height)
967 return BadAlloc;
969 /* thankfully, offset is unsigned */
970 if (stuff->offset + size < size)
971 return BadAlloc;
973 VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
975 if (!(newPix = malloc(sizeof(PanoramiXRes))))
976 return BadAlloc;
978 newPix->type = XRT_PIXMAP;
979 newPix->u.pix.shared = TRUE;
980 panoramix_setup_ids(newPix, client, stuff->pid);
982 result = Success;
984 FOR_NSCREENS(j) {
985 ShmScrPrivateRec *screen_priv;
987 pScreen = screenInfo.screens[j];
989 screen_priv = ShmGetScreenPriv(pScreen);
990 pMap = (*screen_priv->shmFuncs->CreatePixmap) (pScreen,
991 stuff->width,
992 stuff->height,
993 stuff->depth,
994 shmdesc->addr +
995 stuff->offset);
997 if (pMap) {
998 result = XaceHookResourceAccess(client, stuff->pid,
999 X11_RESTYPE_PIXMAP, pMap, X11_RESTYPE_NONE, NULL, DixCreateAccess);
1000 if (result != Success) {
1001 pDraw->pScreen->DestroyPixmap(pMap);
1002 break;
1004 dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
1005 shmdesc->refcnt++;
1006 pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1007 pMap->drawable.id = newPix->info[j].id;
1008 if (!AddResource(newPix->info[j].id, X11_RESTYPE_PIXMAP, (void *) pMap)) {
1009 result = BadAlloc;
1010 break;
1013 else {
1014 result = BadAlloc;
1015 break;
1019 if (result != Success) {
1020 while (j--)
1021 FreeResource(newPix->info[j].id, X11_RESTYPE_NONE);
1022 free(newPix);
1024 else
1025 AddResource(stuff->pid, XRT_PIXMAP, newPix);
1027 return result;
1029 #endif
1031 static PixmapPtr
1032 fbShmCreatePixmap(ScreenPtr pScreen,
1033 int width, int height, int depth, char *addr)
1035 PixmapPtr pPixmap;
1037 pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0);
1038 if (!pPixmap)
1039 return NullPixmap;
1041 if (!(*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth,
1042 BitsPerPixel(depth),
1043 PixmapBytePad(width, depth),
1044 (void *) addr)) {
1045 (*pScreen->DestroyPixmap) (pPixmap);
1046 return NullPixmap;
1048 return pPixmap;
1051 static int
1052 ProcShmCreatePixmap(ClientPtr client)
1054 PixmapPtr pMap;
1055 DrawablePtr pDraw;
1056 DepthPtr pDepth;
1057 int i, rc;
1058 ShmDescPtr shmdesc;
1059 ShmScrPrivateRec *screen_priv;
1061 REQUEST(xShmCreatePixmapReq);
1062 unsigned int width, height, depth;
1063 unsigned long size;
1065 REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1066 client->errorValue = stuff->pid;
1067 if (!sharedPixmaps)
1068 return BadImplementation;
1069 LEGAL_NEW_RESOURCE(stuff->pid, client);
1070 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
1071 DixGetAttrAccess);
1072 if (rc != Success)
1073 return rc;
1075 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
1077 width = stuff->width;
1078 height = stuff->height;
1079 depth = stuff->depth;
1080 if (!width || !height || !depth) {
1081 client->errorValue = 0;
1082 return BadValue;
1084 if (width > 32767 || height > 32767)
1085 return BadAlloc;
1087 if (stuff->depth != 1) {
1088 pDepth = pDraw->pScreen->allowedDepths;
1089 for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
1090 if (pDepth->depth == stuff->depth)
1091 goto CreatePmap;
1092 client->errorValue = stuff->depth;
1093 return BadValue;
1096 CreatePmap:
1097 size = PixmapBytePad(width, depth) * height;
1098 if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
1099 if (size < width * height)
1100 return BadAlloc;
1102 /* thankfully, offset is unsigned */
1103 if (stuff->offset + size < size)
1104 return BadAlloc;
1106 VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
1107 screen_priv = ShmGetScreenPriv(pDraw->pScreen);
1108 pMap = (*screen_priv->shmFuncs->CreatePixmap) (pDraw->pScreen, stuff->width,
1109 stuff->height, stuff->depth,
1110 shmdesc->addr +
1111 stuff->offset);
1112 if (pMap) {
1113 rc = XaceHookResourceAccess(client, stuff->pid, X11_RESTYPE_PIXMAP,
1114 pMap, X11_RESTYPE_NONE, NULL, DixCreateAccess);
1115 if (rc != Success) {
1116 pDraw->pScreen->DestroyPixmap(pMap);
1117 return rc;
1119 dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
1120 shmdesc->refcnt++;
1121 pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1122 pMap->drawable.id = stuff->pid;
1123 if (AddResource(stuff->pid, X11_RESTYPE_PIXMAP, (void *) pMap)) {
1124 return Success;
1127 return BadAlloc;
1130 #ifdef SHM_FD_PASSING
1132 static void
1133 ShmBusfaultNotify(void *context)
1135 ShmDescPtr shmdesc = context;
1137 ErrorF("shared memory 0x%x truncated by client\n",
1138 (unsigned int) shmdesc->resource);
1139 busfault_unregister(shmdesc->busfault);
1140 shmdesc->busfault = NULL;
1141 FreeResource (shmdesc->resource, X11_RESTYPE_NONE);
1144 static int
1145 ProcShmAttachFd(ClientPtr client)
1147 int fd;
1148 ShmDescPtr shmdesc;
1149 REQUEST(xShmAttachFdReq);
1150 struct stat statb;
1152 SetReqFds(client, 1);
1153 REQUEST_SIZE_MATCH(xShmAttachFdReq);
1154 LEGAL_NEW_RESOURCE(stuff->shmseg, client);
1155 if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1156 client->errorValue = stuff->readOnly;
1157 return BadValue;
1159 fd = ReadFdFromClient(client);
1160 if (fd < 0)
1161 return BadMatch;
1163 if (fstat(fd, &statb) < 0 || statb.st_size == 0) {
1164 close(fd);
1165 return BadMatch;
1168 shmdesc = malloc(sizeof(ShmDescRec));
1169 if (!shmdesc) {
1170 close(fd);
1171 return BadAlloc;
1173 shmdesc->is_fd = TRUE;
1174 shmdesc->addr = mmap(NULL, statb.st_size,
1175 stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1176 MAP_SHARED,
1177 fd, 0);
1179 close(fd);
1180 if (shmdesc->addr == ((char *) -1)) {
1181 free(shmdesc);
1182 return BadAccess;
1185 shmdesc->refcnt = 1;
1186 shmdesc->writable = !stuff->readOnly;
1187 shmdesc->size = statb.st_size;
1188 shmdesc->resource = stuff->shmseg;
1190 shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1191 if (!shmdesc->busfault) {
1192 munmap(shmdesc->addr, shmdesc->size);
1193 free(shmdesc);
1194 return BadAlloc;
1197 shmdesc->next = Shmsegs;
1198 Shmsegs = shmdesc;
1200 if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
1201 return BadAlloc;
1202 return Success;
1205 static int
1206 shm_tmpfile(void)
1208 const char *shmdirs[] = {
1209 "/run/shm",
1210 "/var/tmp",
1211 "/tmp",
1213 int fd;
1215 #ifdef HAVE_MEMFD_CREATE
1216 fd = memfd_create("xorg", MFD_CLOEXEC|MFD_ALLOW_SEALING);
1217 if (fd != -1) {
1218 fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
1219 DebugF ("Using memfd_create\n");
1220 return fd;
1222 #endif
1224 #ifdef O_TMPFILE
1225 for (int i = 0; i < ARRAY_SIZE(shmdirs); i++) {
1226 fd = open(shmdirs[i], O_TMPFILE|O_RDWR|O_CLOEXEC|O_EXCL, 0666);
1227 if (fd >= 0) {
1228 DebugF ("Using O_TMPFILE\n");
1229 return fd;
1232 ErrorF ("Not using O_TMPFILE\n");
1233 #endif
1235 for (int i = 0; i < ARRAY_SIZE(shmdirs); i++) {
1236 char template[PATH_MAX];
1237 snprintf(template, ARRAY_SIZE(template), "%s/shmfd-XXXXXX", shmdirs[i]);
1238 #ifdef HAVE_MKOSTEMP
1239 fd = mkostemp(template, O_CLOEXEC);
1240 #else
1241 fd = mkstemp(template);
1242 #endif
1243 if (fd < 0)
1244 continue;
1245 unlink(template);
1246 #ifndef HAVE_MKOSTEMP
1247 int flags = fcntl(fd, F_GETFD);
1248 if (flags != -1) {
1249 flags |= FD_CLOEXEC;
1250 (void) fcntl(fd, F_SETFD, flags);
1252 #endif
1253 return fd;
1256 return -1;
1259 static int
1260 ProcShmCreateSegment(ClientPtr client)
1262 int fd;
1263 ShmDescPtr shmdesc;
1264 REQUEST(xShmCreateSegmentReq);
1265 xShmCreateSegmentReply rep = {
1266 .type = X_Reply,
1267 .nfd = 1,
1268 .sequenceNumber = client->sequence,
1269 .length = 0,
1272 REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
1273 LEGAL_NEW_RESOURCE(stuff->shmseg, client);
1274 if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1275 client->errorValue = stuff->readOnly;
1276 return BadValue;
1278 fd = shm_tmpfile();
1279 if (fd < 0)
1280 return BadAlloc;
1281 if (ftruncate(fd, stuff->size) < 0) {
1282 close(fd);
1283 return BadAlloc;
1285 shmdesc = malloc(sizeof(ShmDescRec));
1286 if (!shmdesc) {
1287 close(fd);
1288 return BadAlloc;
1290 shmdesc->is_fd = TRUE;
1291 shmdesc->addr = mmap(NULL, stuff->size,
1292 stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1293 MAP_SHARED,
1294 fd, 0);
1296 if (shmdesc->addr == ((char *) -1)) {
1297 close(fd);
1298 free(shmdesc);
1299 return BadAccess;
1302 shmdesc->refcnt = 1;
1303 shmdesc->writable = !stuff->readOnly;
1304 shmdesc->size = stuff->size;
1306 shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1307 if (!shmdesc->busfault) {
1308 close(fd);
1309 munmap(shmdesc->addr, shmdesc->size);
1310 free(shmdesc);
1311 return BadAlloc;
1314 shmdesc->next = Shmsegs;
1315 Shmsegs = shmdesc;
1317 if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc)) {
1318 close(fd);
1319 return BadAlloc;
1322 if (WriteFdToClient(client, fd, TRUE) < 0) {
1323 FreeResource(stuff->shmseg, X11_RESTYPE_NONE);
1324 close(fd);
1325 return BadAlloc;
1327 WriteToClient(client, sizeof (xShmCreateSegmentReply), &rep);
1328 return Success;
1330 #endif /* SHM_FD_PASSING */
1332 static int
1333 ProcShmDispatch(ClientPtr client)
1335 REQUEST(xReq);
1337 if (stuff->data == X_ShmQueryVersion)
1338 return ProcShmQueryVersion(client);
1340 if (!client->local)
1341 return BadRequest;
1343 switch (stuff->data) {
1344 case X_ShmAttach:
1345 return ProcShmAttach(client);
1346 case X_ShmDetach:
1347 return ProcShmDetach(client);
1348 case X_ShmPutImage:
1349 #ifdef PANORAMIX
1350 if (!noPanoramiXExtension)
1351 return ProcPanoramiXShmPutImage(client);
1352 #endif
1353 return ProcShmPutImage(client);
1354 case X_ShmGetImage:
1355 #ifdef PANORAMIX
1356 if (!noPanoramiXExtension)
1357 return ProcPanoramiXShmGetImage(client);
1358 #endif
1359 return ProcShmGetImage(client);
1360 case X_ShmCreatePixmap:
1361 #ifdef PANORAMIX
1362 if (!noPanoramiXExtension)
1363 return ProcPanoramiXShmCreatePixmap(client);
1364 #endif
1365 return ProcShmCreatePixmap(client);
1366 #ifdef SHM_FD_PASSING
1367 case X_ShmAttachFd:
1368 return ProcShmAttachFd(client);
1369 case X_ShmCreateSegment:
1370 return ProcShmCreateSegment(client);
1371 #endif
1372 default:
1373 return BadRequest;
1377 static void _X_COLD
1378 SShmCompletionEvent(xShmCompletionEvent * from, xShmCompletionEvent * to)
1380 to->type = from->type;
1381 cpswaps(from->sequenceNumber, to->sequenceNumber);
1382 cpswapl(from->drawable, to->drawable);
1383 cpswaps(from->minorEvent, to->minorEvent);
1384 to->majorEvent = from->majorEvent;
1385 cpswapl(from->shmseg, to->shmseg);
1386 cpswapl(from->offset, to->offset);
1389 static int _X_COLD
1390 SProcShmQueryVersion(ClientPtr client)
1392 REQUEST(xShmQueryVersionReq);
1394 swaps(&stuff->length);
1395 return ProcShmQueryVersion(client);
1398 static int _X_COLD
1399 SProcShmAttach(ClientPtr client)
1401 REQUEST(xShmAttachReq);
1402 swaps(&stuff->length);
1403 REQUEST_SIZE_MATCH(xShmAttachReq);
1404 swapl(&stuff->shmseg);
1405 swapl(&stuff->shmid);
1406 return ProcShmAttach(client);
1409 static int _X_COLD
1410 SProcShmDetach(ClientPtr client)
1412 REQUEST(xShmDetachReq);
1413 swaps(&stuff->length);
1414 REQUEST_SIZE_MATCH(xShmDetachReq);
1415 swapl(&stuff->shmseg);
1416 return ProcShmDetach(client);
1419 static int _X_COLD
1420 SProcShmPutImage(ClientPtr client)
1422 REQUEST(xShmPutImageReq);
1423 swaps(&stuff->length);
1424 REQUEST_SIZE_MATCH(xShmPutImageReq);
1425 swapl(&stuff->drawable);
1426 swapl(&stuff->gc);
1427 swaps(&stuff->totalWidth);
1428 swaps(&stuff->totalHeight);
1429 swaps(&stuff->srcX);
1430 swaps(&stuff->srcY);
1431 swaps(&stuff->srcWidth);
1432 swaps(&stuff->srcHeight);
1433 swaps(&stuff->dstX);
1434 swaps(&stuff->dstY);
1435 swapl(&stuff->shmseg);
1436 swapl(&stuff->offset);
1437 return ProcShmPutImage(client);
1440 static int _X_COLD
1441 SProcShmGetImage(ClientPtr client)
1443 REQUEST(xShmGetImageReq);
1444 swaps(&stuff->length);
1445 REQUEST_SIZE_MATCH(xShmGetImageReq);
1446 swapl(&stuff->drawable);
1447 swaps(&stuff->x);
1448 swaps(&stuff->y);
1449 swaps(&stuff->width);
1450 swaps(&stuff->height);
1451 swapl(&stuff->planeMask);
1452 swapl(&stuff->shmseg);
1453 swapl(&stuff->offset);
1454 return ProcShmGetImage(client);
1457 static int _X_COLD
1458 SProcShmCreatePixmap(ClientPtr client)
1460 REQUEST(xShmCreatePixmapReq);
1461 swaps(&stuff->length);
1462 REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1463 swapl(&stuff->pid);
1464 swapl(&stuff->drawable);
1465 swaps(&stuff->width);
1466 swaps(&stuff->height);
1467 swapl(&stuff->shmseg);
1468 swapl(&stuff->offset);
1469 return ProcShmCreatePixmap(client);
1472 #ifdef SHM_FD_PASSING
1473 static int _X_COLD
1474 SProcShmAttachFd(ClientPtr client)
1476 REQUEST(xShmAttachFdReq);
1477 SetReqFds(client, 1);
1478 swaps(&stuff->length);
1479 REQUEST_SIZE_MATCH(xShmAttachFdReq);
1480 swapl(&stuff->shmseg);
1481 return ProcShmAttachFd(client);
1484 static int _X_COLD
1485 SProcShmCreateSegment(ClientPtr client)
1487 REQUEST(xShmCreateSegmentReq);
1488 swaps(&stuff->length);
1489 REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
1490 swapl(&stuff->shmseg);
1491 swapl(&stuff->size);
1492 return ProcShmCreateSegment(client);
1494 #endif /* SHM_FD_PASSING */
1496 static int _X_COLD
1497 SProcShmDispatch(ClientPtr client)
1499 REQUEST(xReq);
1501 if (stuff->data == X_ShmQueryVersion)
1502 return SProcShmQueryVersion(client);
1504 if (!client->local)
1505 return BadRequest;
1507 switch (stuff->data) {
1508 case X_ShmAttach:
1509 return SProcShmAttach(client);
1510 case X_ShmDetach:
1511 return SProcShmDetach(client);
1512 case X_ShmPutImage:
1513 return SProcShmPutImage(client);
1514 case X_ShmGetImage:
1515 return SProcShmGetImage(client);
1516 case X_ShmCreatePixmap:
1517 return SProcShmCreatePixmap(client);
1518 #ifdef SHM_FD_PASSING
1519 case X_ShmAttachFd:
1520 return SProcShmAttachFd(client);
1521 case X_ShmCreateSegment:
1522 return SProcShmCreateSegment(client);
1523 #endif
1524 default:
1525 return BadRequest;
1529 void
1530 ShmExtensionInit(void)
1532 ExtensionEntry *extEntry;
1533 int i;
1535 #ifdef MUST_CHECK_FOR_SHM_SYSCALL
1536 if (!CheckForShmSyscall()) {
1537 ErrorF("MIT-SHM extension disabled due to lack of kernel support\n");
1538 return;
1540 #endif
1542 if (!ShmRegisterPrivates())
1543 return;
1545 sharedPixmaps = xFalse;
1547 sharedPixmaps = xTrue;
1548 for (i = 0; i < screenInfo.numScreens; i++) {
1549 ShmScrPrivateRec *screen_priv =
1550 ShmInitScreenPriv(screenInfo.screens[i]);
1551 if (!screen_priv->shmFuncs)
1552 screen_priv->shmFuncs = &miFuncs;
1553 if (!screen_priv->shmFuncs->CreatePixmap)
1554 sharedPixmaps = xFalse;
1556 if (sharedPixmaps)
1557 for (i = 0; i < screenInfo.numScreens; i++) {
1558 ShmScrPrivateRec *screen_priv =
1559 ShmGetScreenPriv(screenInfo.screens[i]);
1560 screen_priv->destroyPixmap =
1561 screenInfo.screens[i]->DestroyPixmap;
1562 screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap;
1565 ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg");
1566 if (ShmSegType &&
1567 (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors,
1568 ProcShmDispatch, SProcShmDispatch,
1569 ShmResetProc, StandardMinorOpcode))) {
1570 ShmReqCode = (unsigned char) extEntry->base;
1571 ShmCompletionCode = extEntry->eventBase;
1572 BadShmSegCode = extEntry->errorBase;
1573 SetResourceTypeErrorValue(ShmSegType, BadShmSegCode);
1574 EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent;