Imported Upstream version 1.15.1
[deb_xorg-server.git] / Xext / shm.c
CommitLineData
a09e091a
JB
1/************************************************************
2
3Copyright 1989, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25********************************************************/
26
27/* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */
28
29#define SHM
30
31#ifdef HAVE_DIX_CONFIG_H
32#include <dix-config.h>
33#endif
34
35#include <sys/types.h>
36#include <sys/ipc.h>
37#include <sys/shm.h>
38#include <unistd.h>
39#include <sys/stat.h>
40#include <fcntl.h>
41#include <X11/X.h>
42#include <X11/Xproto.h>
43#include "misc.h"
44#include "os.h"
45#include "dixstruct.h"
46#include "resource.h"
47#include "scrnintstr.h"
48#include "windowstr.h"
49#include "pixmapstr.h"
50#include "gcstruct.h"
51#include "extnsionst.h"
52#include "servermd.h"
53#include "shmint.h"
54#include "xace.h"
55#include <X11/extensions/shmproto.h>
56#include <X11/Xfuncproto.h>
57#include <sys/mman.h>
58#include "protocol-versions.h"
59#include "busfault.h"
60
61/* Needed for Solaris cross-zone shared memory extension */
62#ifdef HAVE_SHMCTL64
63#include <sys/ipc_impl.h>
64#define SHMSTAT(id, buf) shmctl64(id, IPC_STAT64, buf)
65#define SHMSTAT_TYPE struct shmid_ds64
66#define SHMPERM_TYPE struct ipc_perm64
67#define SHM_PERM(buf) buf.shmx_perm
68#define SHM_SEGSZ(buf) buf.shmx_segsz
69#define SHMPERM_UID(p) p->ipcx_uid
70#define SHMPERM_CUID(p) p->ipcx_cuid
71#define SHMPERM_GID(p) p->ipcx_gid
72#define SHMPERM_CGID(p) p->ipcx_cgid
73#define SHMPERM_MODE(p) p->ipcx_mode
74#define SHMPERM_ZONEID(p) p->ipcx_zoneid
75#else
76#define SHMSTAT(id, buf) shmctl(id, IPC_STAT, buf)
77#define SHMSTAT_TYPE struct shmid_ds
78#define SHMPERM_TYPE struct ipc_perm
79#define SHM_PERM(buf) buf.shm_perm
80#define SHM_SEGSZ(buf) buf.shm_segsz
81#define SHMPERM_UID(p) p->uid
82#define SHMPERM_CUID(p) p->cuid
83#define SHMPERM_GID(p) p->gid
84#define SHMPERM_CGID(p) p->cgid
85#define SHMPERM_MODE(p) p->mode
86#endif
87
88#ifdef PANORAMIX
89#include "panoramiX.h"
90#include "panoramiXsrv.h"
91#endif
92
93#include "extinit.h"
94
95typedef struct _ShmScrPrivateRec {
96 CloseScreenProcPtr CloseScreen;
97 ShmFuncsPtr shmFuncs;
98 DestroyPixmapProcPtr destroyPixmap;
99} ShmScrPrivateRec;
100
101static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS);
102static int ShmDetachSegment(pointer /* value */ ,
103 XID /* shmseg */
104 );
105static void ShmResetProc(ExtensionEntry * /* extEntry */
106 );
107static void SShmCompletionEvent(xShmCompletionEvent * /* from */ ,
108 xShmCompletionEvent * /* to */
109 );
110
111static Bool ShmDestroyPixmap(PixmapPtr pPixmap);
112
113static unsigned char ShmReqCode;
114int ShmCompletionCode;
115int BadShmSegCode;
116RESTYPE ShmSegType;
117static ShmDescPtr Shmsegs;
118static Bool sharedPixmaps;
119static DevPrivateKeyRec shmScrPrivateKeyRec;
120
121#define shmScrPrivateKey (&shmScrPrivateKeyRec)
122static DevPrivateKeyRec shmPixmapPrivateKeyRec;
123
124#define shmPixmapPrivateKey (&shmPixmapPrivateKeyRec)
125static ShmFuncs miFuncs = { NULL, NULL };
126static ShmFuncs fbFuncs = { fbShmCreatePixmap, NULL };
127
128#define ShmGetScreenPriv(s) ((ShmScrPrivateRec *)dixLookupPrivate(&(s)->devPrivates, shmScrPrivateKey))
129
130#define VERIFY_SHMSEG(shmseg,shmdesc,client) \
131{ \
132 int tmprc; \
133 tmprc = dixLookupResourceByType((pointer *)&(shmdesc), shmseg, ShmSegType, \
134 client, DixReadAccess); \
135 if (tmprc != Success) \
136 return tmprc; \
137}
138
139#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \
140{ \
141 VERIFY_SHMSEG(shmseg, shmdesc, client); \
142 if ((offset & 3) || (offset > shmdesc->size)) \
143 { \
144 client->errorValue = offset; \
145 return BadValue; \
146 } \
147 if (needwrite && !shmdesc->writable) \
148 return BadAccess; \
149}
150
151#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \
152{ \
153 if ((offset + len) > shmdesc->size) \
154 { \
155 return BadAccess; \
156 } \
157}
158
159#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
160#include <sys/signal.h>
161
162static Bool badSysCall = FALSE;
163
164static void
165SigSysHandler(int signo)
166{
167 badSysCall = TRUE;
168}
169
170static Bool
171CheckForShmSyscall(void)
172{
173 void (*oldHandler) (int);
174 int shmid = -1;
175
176 /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
177 oldHandler = signal(SIGSYS, SigSysHandler);
178
179 badSysCall = FALSE;
180 shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
181
182 if (shmid != -1) {
183 /* Successful allocation - clean up */
184 shmctl(shmid, IPC_RMID, NULL);
185 }
186 else {
187 /* Allocation failed */
188 badSysCall = TRUE;
189 }
190 signal(SIGSYS, oldHandler);
191 return !badSysCall;
192}
193
194#define MUST_CHECK_FOR_SHM_SYSCALL
195
196#endif
197
198static Bool
199ShmCloseScreen(ScreenPtr pScreen)
200{
201 ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
202
203 pScreen->CloseScreen = screen_priv->CloseScreen;
204 dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL);
205 free(screen_priv);
206 return (*pScreen->CloseScreen) (pScreen);
207}
208
209static ShmScrPrivateRec *
210ShmInitScreenPriv(ScreenPtr pScreen)
211{
212 ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
213
214 if (!screen_priv) {
215 screen_priv = calloc(1, sizeof(ShmScrPrivateRec));
216 screen_priv->CloseScreen = pScreen->CloseScreen;
217 dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv);
218 pScreen->CloseScreen = ShmCloseScreen;
219 }
220 return screen_priv;
221}
222
223static Bool
224ShmRegisterPrivates(void)
225{
226 if (!dixRegisterPrivateKey(&shmScrPrivateKeyRec, PRIVATE_SCREEN, 0))
227 return FALSE;
228 if (!dixRegisterPrivateKey(&shmPixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
229 return FALSE;
230 return TRUE;
231}
232
233 /*ARGSUSED*/ static void
234ShmResetProc(ExtensionEntry * extEntry)
235{
236 int i;
237
238 for (i = 0; i < screenInfo.numScreens; i++)
239 ShmRegisterFuncs(screenInfo.screens[i], NULL);
240}
241
242void
243ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs)
244{
245 if (!ShmRegisterPrivates())
246 return;
247 ShmInitScreenPriv(pScreen)->shmFuncs = funcs;
248}
249
250static Bool
251ShmDestroyPixmap(PixmapPtr pPixmap)
252{
253 ScreenPtr pScreen = pPixmap->drawable.pScreen;
254 ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
255 Bool ret;
256
257 if (pPixmap->refcnt == 1) {
258 ShmDescPtr shmdesc;
259
260 shmdesc = (ShmDescPtr) dixLookupPrivate(&pPixmap->devPrivates,
261 shmPixmapPrivateKey);
262 if (shmdesc)
263 ShmDetachSegment((pointer) shmdesc, pPixmap->drawable.id);
264 }
265
266 pScreen->DestroyPixmap = screen_priv->destroyPixmap;
267 ret = (*pScreen->DestroyPixmap) (pPixmap);
268 screen_priv->destroyPixmap = pScreen->DestroyPixmap;
269 pScreen->DestroyPixmap = ShmDestroyPixmap;
270 return ret;
271}
272
273void
274ShmRegisterFbFuncs(ScreenPtr pScreen)
275{
276 ShmRegisterFuncs(pScreen, &fbFuncs);
277}
278
279static int
280ProcShmQueryVersion(ClientPtr client)
281{
282 xShmQueryVersionReply rep = {
283 .type = X_Reply,
284 .sharedPixmaps = sharedPixmaps,
285 .sequenceNumber = client->sequence,
286 .length = 0,
287 .majorVersion = SERVER_SHM_MAJOR_VERSION,
288 .minorVersion = SERVER_SHM_MINOR_VERSION,
289 .uid = geteuid(),
290 .gid = getegid(),
291 .pixmapFormat = sharedPixmaps ? ZPixmap : 0
292 };
293
294 REQUEST_SIZE_MATCH(xShmQueryVersionReq);
295
296 if (client->swapped) {
297 swaps(&rep.sequenceNumber);
298 swapl(&rep.length);
299 swaps(&rep.majorVersion);
300 swaps(&rep.minorVersion);
301 swaps(&rep.uid);
302 swaps(&rep.gid);
303 }
304 WriteToClient(client, sizeof(xShmQueryVersionReply), &rep);
305 return Success;
306}
307
308/*
309 * Simulate the access() system call for a shared memory segement,
310 * using the credentials from the client if available
311 */
312static int
313shm_access(ClientPtr client, SHMPERM_TYPE * perm, int readonly)
314{
315 int uid, gid;
316 mode_t mask;
317 int uidset = 0, gidset = 0;
318 LocalClientCredRec *lcc;
319
320 if (GetLocalClientCreds(client, &lcc) != -1) {
321
322 if (lcc->fieldsSet & LCC_UID_SET) {
323 uid = lcc->euid;
324 uidset = 1;
325 }
326 if (lcc->fieldsSet & LCC_GID_SET) {
327 gid = lcc->egid;
328 gidset = 1;
329 }
330
331#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID)
332 if (((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1)
333 || (lcc->zoneid != SHMPERM_ZONEID(perm))) {
334 uidset = 0;
335 gidset = 0;
336 }
337#endif
338 FreeLocalClientCreds(lcc);
339
340 if (uidset) {
341 /* User id 0 always gets access */
342 if (uid == 0) {
343 return 0;
344 }
345 /* Check the owner */
346 if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) {
347 mask = S_IRUSR;
348 if (!readonly) {
349 mask |= S_IWUSR;
350 }
351 return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
352 }
353 }
354
355 if (gidset) {
356 /* Check the group */
357 if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) {
358 mask = S_IRGRP;
359 if (!readonly) {
360 mask |= S_IWGRP;
361 }
362 return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
363 }
364 }
365 }
366 /* Otherwise, check everyone else */
367 mask = S_IROTH;
368 if (!readonly) {
369 mask |= S_IWOTH;
370 }
371 return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
372}
373
374static int
375ProcShmAttach(ClientPtr client)
376{
377 SHMSTAT_TYPE buf;
378 ShmDescPtr shmdesc;
379
380 REQUEST(xShmAttachReq);
381
382 REQUEST_SIZE_MATCH(xShmAttachReq);
383 LEGAL_NEW_RESOURCE(stuff->shmseg, client);
384 if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
385 client->errorValue = stuff->readOnly;
386 return BadValue;
387 }
388 for (shmdesc = Shmsegs; shmdesc; shmdesc = shmdesc->next) {
389 if (!SHMDESC_IS_FD(shmdesc) && shmdesc->shmid == stuff->shmid)
390 break;
391 }
392 if (shmdesc) {
393 if (!stuff->readOnly && !shmdesc->writable)
394 return BadAccess;
395 shmdesc->refcnt++;
396 }
397 else {
398 shmdesc = malloc(sizeof(ShmDescRec));
399 if (!shmdesc)
400 return BadAlloc;
401#ifdef SHM_FD_PASSING
402 shmdesc->is_fd = FALSE;
403#endif
404 shmdesc->addr = shmat(stuff->shmid, 0,
405 stuff->readOnly ? SHM_RDONLY : 0);
406 if ((shmdesc->addr == ((char *) -1)) || SHMSTAT(stuff->shmid, &buf)) {
407 free(shmdesc);
408 return BadAccess;
409 }
410
411 /* The attach was performed with root privs. We must
412 * do manual checking of access rights for the credentials
413 * of the client */
414
415 if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) {
416 shmdt(shmdesc->addr);
417 free(shmdesc);
418 return BadAccess;
419 }
420
421 shmdesc->shmid = stuff->shmid;
422 shmdesc->refcnt = 1;
423 shmdesc->writable = !stuff->readOnly;
424 shmdesc->size = SHM_SEGSZ(buf);
425 shmdesc->next = Shmsegs;
426 Shmsegs = shmdesc;
427 }
428 if (!AddResource(stuff->shmseg, ShmSegType, (pointer) shmdesc))
429 return BadAlloc;
430 return Success;
431}
432
433 /*ARGSUSED*/ static int
434ShmDetachSegment(pointer value, /* must conform to DeleteType */
435 XID shmseg)
436{
437 ShmDescPtr shmdesc = (ShmDescPtr) value;
438 ShmDescPtr *prev;
439
440 if (--shmdesc->refcnt)
441 return TRUE;
442#if SHM_FD_PASSING
443 if (shmdesc->is_fd) {
444 if (shmdesc->busfault)
445 busfault_unregister(shmdesc->busfault);
446 munmap(shmdesc->addr, shmdesc->size);
447 } else
448#endif
449 shmdt(shmdesc->addr);
450 for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next);
451 *prev = shmdesc->next;
452 free(shmdesc);
453 return Success;
454}
455
456static int
457ProcShmDetach(ClientPtr client)
458{
459 ShmDescPtr shmdesc;
460
461 REQUEST(xShmDetachReq);
462
463 REQUEST_SIZE_MATCH(xShmDetachReq);
464 VERIFY_SHMSEG(stuff->shmseg, shmdesc, client);
465 FreeResource(stuff->shmseg, RT_NONE);
466 return Success;
467}
468
469/*
470 * If the given request doesn't exactly match PutImage's constraints,
471 * wrap the image in a scratch pixmap header and let CopyArea sort it out.
472 */
473static void
474doShmPutImage(DrawablePtr dst, GCPtr pGC,
475 int depth, unsigned int format,
476 int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
477 char *data)
478{
479 PixmapPtr pPixmap;
480
481 if (format == ZPixmap || (format == XYPixmap && depth == 1)) {
482 pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth,
483 BitsPerPixel(depth),
484 PixmapBytePad(w, depth), data);
485 if (!pPixmap)
486 return;
487 pGC->ops->CopyArea((DrawablePtr) pPixmap, dst, pGC, sx, sy, sw, sh, dx,
488 dy);
489 FreeScratchPixmapHeader(pPixmap);
490 }
491 else {
492 GCPtr putGC = GetScratchGC(depth, dst->pScreen);
493
494 if (!putGC)
495 return;
496
497 pPixmap = (*dst->pScreen->CreatePixmap) (dst->pScreen, sw, sh, depth,
498 CREATE_PIXMAP_USAGE_SCRATCH);
499 if (!pPixmap) {
500 FreeScratchGC(putGC);
501 return;
502 }
503 ValidateGC(&pPixmap->drawable, putGC);
504 (*putGC->ops->PutImage) (&pPixmap->drawable, putGC, depth, -sx, -sy, w,
505 h, 0,
506 (format == XYPixmap) ? XYPixmap : ZPixmap,
507 data);
508 FreeScratchGC(putGC);
509 if (format == XYBitmap)
510 (void) (*pGC->ops->CopyPlane) (&pPixmap->drawable, dst, pGC, 0, 0,
511 sw, sh, dx, dy, 1L);
512 else
513 (void) (*pGC->ops->CopyArea) (&pPixmap->drawable, dst, pGC, 0, 0,
514 sw, sh, dx, dy);
515 (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap);
516 }
517}
518
519static int
520ProcShmPutImage(ClientPtr client)
521{
522 GCPtr pGC;
523 DrawablePtr pDraw;
524 long length;
525 ShmDescPtr shmdesc;
526
527 REQUEST(xShmPutImageReq);
528
529 REQUEST_SIZE_MATCH(xShmPutImageReq);
530 VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
531 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client);
532 if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse))
533 return BadValue;
534 if (stuff->format == XYBitmap) {
535 if (stuff->depth != 1)
536 return BadMatch;
537 length = PixmapBytePad(stuff->totalWidth, 1);
538 }
539 else if (stuff->format == XYPixmap) {
540 if (pDraw->depth != stuff->depth)
541 return BadMatch;
542 length = PixmapBytePad(stuff->totalWidth, 1);
543 length *= stuff->depth;
544 }
545 else if (stuff->format == ZPixmap) {
546 if (pDraw->depth != stuff->depth)
547 return BadMatch;
548 length = PixmapBytePad(stuff->totalWidth, stuff->depth);
549 }
550 else {
551 client->errorValue = stuff->format;
552 return BadValue;
553 }
554
555 /*
556 * There's a potential integer overflow in this check:
557 * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight,
558 * client);
559 * the version below ought to avoid it
560 */
561 if (stuff->totalHeight != 0 &&
562 length > (shmdesc->size - stuff->offset) / stuff->totalHeight) {
563 client->errorValue = stuff->totalWidth;
564 return BadValue;
565 }
566 if (stuff->srcX > stuff->totalWidth) {
567 client->errorValue = stuff->srcX;
568 return BadValue;
569 }
570 if (stuff->srcY > stuff->totalHeight) {
571 client->errorValue = stuff->srcY;
572 return BadValue;
573 }
574 if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) {
575 client->errorValue = stuff->srcWidth;
576 return BadValue;
577 }
578 if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) {
579 client->errorValue = stuff->srcHeight;
580 return BadValue;
581 }
582
583 if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) ||
584 ((stuff->format != ZPixmap) &&
585 (stuff->srcX < screenInfo.bitmapScanlinePad) &&
586 ((stuff->format == XYBitmap) ||
587 ((stuff->srcY == 0) &&
588 (stuff->srcHeight == stuff->totalHeight))))) &&
589 ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth))
590 (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth,
591 stuff->dstX, stuff->dstY,
592 stuff->totalWidth, stuff->srcHeight,
593 stuff->srcX, stuff->format,
594 shmdesc->addr + stuff->offset +
595 (stuff->srcY * length));
596 else
597 doShmPutImage(pDraw, pGC, stuff->depth, stuff->format,
598 stuff->totalWidth, stuff->totalHeight,
599 stuff->srcX, stuff->srcY,
600 stuff->srcWidth, stuff->srcHeight,
601 stuff->dstX, stuff->dstY, shmdesc->addr + stuff->offset);
602
603 if (stuff->sendEvent) {
604 xShmCompletionEvent ev = {
605 .type = ShmCompletionCode,
606 .drawable = stuff->drawable,
607 .minorEvent = X_ShmPutImage,
608 .majorEvent = ShmReqCode,
609 .shmseg = stuff->shmseg,
610 .offset = stuff->offset
611 };
612 WriteEventsToClient(client, 1, (xEvent *) &ev);
613 }
614
615 return Success;
616}
617
618static int
619ProcShmGetImage(ClientPtr client)
620{
621 DrawablePtr pDraw;
622 long lenPer = 0, length;
623 Mask plane = 0;
624 xShmGetImageReply xgi;
625 ShmDescPtr shmdesc;
626 VisualID visual = None;
627 int rc;
628
629 REQUEST(xShmGetImageReq);
630
631 REQUEST_SIZE_MATCH(xShmGetImageReq);
632 if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
633 client->errorValue = stuff->format;
634 return BadValue;
635 }
636 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
637 if (rc != Success)
638 return rc;
639 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
640 if (pDraw->type == DRAWABLE_WINDOW) {
641 if ( /* check for being viewable */
642 !((WindowPtr) pDraw)->realized ||
643 /* check for being on screen */
644 pDraw->x + stuff->x < 0 ||
645 pDraw->x + stuff->x + (int) stuff->width > pDraw->pScreen->width
646 || pDraw->y + stuff->y < 0 ||
647 pDraw->y + stuff->y + (int) stuff->height >
648 pDraw->pScreen->height ||
649 /* check for being inside of border */
650 stuff->x < -wBorderWidth((WindowPtr) pDraw) ||
651 stuff->x + (int) stuff->width >
652 wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
653 stuff->y < -wBorderWidth((WindowPtr) pDraw) ||
654 stuff->y + (int) stuff->height >
655 wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
656 return BadMatch;
657 visual = wVisual(((WindowPtr) pDraw));
658 }
659 else {
660 if (stuff->x < 0 ||
661 stuff->x + (int) stuff->width > pDraw->width ||
662 stuff->y < 0 || stuff->y + (int) stuff->height > pDraw->height)
663 return BadMatch;
664 visual = None;
665 }
666 xgi = (xShmGetImageReply) {
667 .type = X_Reply,
668 .sequenceNumber = client->sequence,
669 .length = 0,
670 .visual = visual,
671 .depth = pDraw->depth
672 };
673 if (stuff->format == ZPixmap) {
674 length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height;
675 }
676 else {
677 lenPer = PixmapBytePad(stuff->width, 1) * stuff->height;
678 plane = ((Mask) 1) << (pDraw->depth - 1);
679 /* only planes asked for */
680 length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
681 }
682
683 VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
684 xgi.size = length;
685
686 if (length == 0) {
687 /* nothing to do */
688 }
689 else if (stuff->format == ZPixmap) {
690 (*pDraw->pScreen->GetImage) (pDraw, stuff->x, stuff->y,
691 stuff->width, stuff->height,
692 stuff->format, stuff->planeMask,
693 shmdesc->addr + stuff->offset);
694 }
695 else {
696
697 length = stuff->offset;
698 for (; plane; plane >>= 1) {
699 if (stuff->planeMask & plane) {
700 (*pDraw->pScreen->GetImage) (pDraw,
701 stuff->x, stuff->y,
702 stuff->width, stuff->height,
703 stuff->format, plane,
704 shmdesc->addr + length);
705 length += lenPer;
706 }
707 }
708 }
709
710 if (client->swapped) {
711 swaps(&xgi.sequenceNumber);
712 swapl(&xgi.length);
713 swapl(&xgi.visual);
714 swapl(&xgi.size);
715 }
716 WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
717
718 return Success;
719}
720
721#ifdef PANORAMIX
722static int
723ProcPanoramiXShmPutImage(ClientPtr client)
724{
725 int j, result, orig_x, orig_y;
726 PanoramiXRes *draw, *gc;
727 Bool sendEvent, isRoot;
728
729 REQUEST(xShmPutImageReq);
730 REQUEST_SIZE_MATCH(xShmPutImageReq);
731
732 result = dixLookupResourceByClass((pointer *) &draw, stuff->drawable,
733 XRC_DRAWABLE, client, DixWriteAccess);
734 if (result != Success)
735 return (result == BadValue) ? BadDrawable : result;
736
737 result = dixLookupResourceByType((pointer *) &gc, stuff->gc,
738 XRT_GC, client, DixReadAccess);
739 if (result != Success)
740 return result;
741
742 isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
743
744 orig_x = stuff->dstX;
745 orig_y = stuff->dstY;
746 sendEvent = stuff->sendEvent;
747 stuff->sendEvent = 0;
748 FOR_NSCREENS(j) {
749 if (!j)
750 stuff->sendEvent = sendEvent;
751 stuff->drawable = draw->info[j].id;
752 stuff->gc = gc->info[j].id;
753 if (isRoot) {
754 stuff->dstX = orig_x - screenInfo.screens[j]->x;
755 stuff->dstY = orig_y - screenInfo.screens[j]->y;
756 }
757 result = ProcShmPutImage(client);
758 if (result != Success)
759 break;
760 }
761 return result;
762}
763
764static int
765ProcPanoramiXShmGetImage(ClientPtr client)
766{
767 PanoramiXRes *draw;
768 DrawablePtr *drawables;
769 DrawablePtr pDraw;
770 xShmGetImageReply xgi;
771 ShmDescPtr shmdesc;
772 int i, x, y, w, h, format, rc;
773 Mask plane = 0, planemask;
774 long lenPer = 0, length, widthBytesLine;
775 Bool isRoot;
776
777 REQUEST(xShmGetImageReq);
778
779 REQUEST_SIZE_MATCH(xShmGetImageReq);
780
781 if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
782 client->errorValue = stuff->format;
783 return BadValue;
784 }
785
786 rc = dixLookupResourceByClass((pointer *) &draw, stuff->drawable,
787 XRC_DRAWABLE, client, DixWriteAccess);
788 if (rc != Success)
789 return (rc == BadValue) ? BadDrawable : rc;
790
791 if (draw->type == XRT_PIXMAP)
792 return ProcShmGetImage(client);
793
794 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
795 if (rc != Success)
796 return rc;
797
798 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
799
800 x = stuff->x;
801 y = stuff->y;
802 w = stuff->width;
803 h = stuff->height;
804 format = stuff->format;
805 planemask = stuff->planeMask;
806
807 isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
808
809 if (isRoot) {
810 if ( /* check for being onscreen */
811 x < 0 || x + w > PanoramiXPixWidth ||
812 y < 0 || y + h > PanoramiXPixHeight)
813 return BadMatch;
814 }
815 else {
816 if ( /* check for being onscreen */
817 screenInfo.screens[0]->x + pDraw->x + x < 0 ||
818 screenInfo.screens[0]->x + pDraw->x + x + w > PanoramiXPixWidth
819 || screenInfo.screens[0]->y + pDraw->y + y < 0 ||
820 screenInfo.screens[0]->y + pDraw->y + y + h > PanoramiXPixHeight
821 ||
822 /* check for being inside of border */
823 x < -wBorderWidth((WindowPtr) pDraw) ||
824 x + w > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
825 y < -wBorderWidth((WindowPtr) pDraw) ||
826 y + h > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
827 return BadMatch;
828 }
829
830 drawables = calloc(PanoramiXNumScreens, sizeof(DrawablePtr));
831 if (!drawables)
832 return BadAlloc;
833
834 drawables[0] = pDraw;
835 FOR_NSCREENS_FORWARD_SKIP(i) {
836 rc = dixLookupDrawable(drawables + i, draw->info[i].id, client, 0,
837 DixReadAccess);
838 if (rc != Success) {
839 free(drawables);
840 return rc;
841 }
842 }
843
844 xgi = (xShmGetImageReply) {
845 .type = X_Reply,
846 .sequenceNumber = client->sequence,
847 .length = 0,
848 .visual = wVisual(((WindowPtr) pDraw)),
849 .depth = pDraw->depth
850 };
851
852 if (format == ZPixmap) {
853 widthBytesLine = PixmapBytePad(w, pDraw->depth);
854 length = widthBytesLine * h;
855 }
856 else {
857 widthBytesLine = PixmapBytePad(w, 1);
858 lenPer = widthBytesLine * h;
859 plane = ((Mask) 1) << (pDraw->depth - 1);
860 length = lenPer * Ones(planemask & (plane | (plane - 1)));
861 }
862
863 VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
864 xgi.size = length;
865
866 if (length == 0) { /* nothing to do */
867 }
868 else if (format == ZPixmap) {
869 XineramaGetImageData(drawables, x, y, w, h, format, planemask,
870 shmdesc->addr + stuff->offset,
871 widthBytesLine, isRoot);
872 }
873 else {
874
875 length = stuff->offset;
876 for (; plane; plane >>= 1) {
877 if (planemask & plane) {
878 XineramaGetImageData(drawables, x, y, w, h,
879 format, plane, shmdesc->addr + length,
880 widthBytesLine, isRoot);
881 length += lenPer;
882 }
883 }
884 }
885 free(drawables);
886
887 if (client->swapped) {
888 swaps(&xgi.sequenceNumber);
889 swapl(&xgi.length);
890 swapl(&xgi.visual);
891 swapl(&xgi.size);
892 }
893 WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
894
895 return Success;
896}
897
898static int
899ProcPanoramiXShmCreatePixmap(ClientPtr client)
900{
901 ScreenPtr pScreen = NULL;
902 PixmapPtr pMap = NULL;
903 DrawablePtr pDraw;
904 DepthPtr pDepth;
905 int i, j, result, rc;
906 ShmDescPtr shmdesc;
907
908 REQUEST(xShmCreatePixmapReq);
909 unsigned int width, height, depth;
910 unsigned long size;
911 PanoramiXRes *newPix;
912
913 REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
914 client->errorValue = stuff->pid;
915 if (!sharedPixmaps)
916 return BadImplementation;
917 LEGAL_NEW_RESOURCE(stuff->pid, client);
918 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
919 DixGetAttrAccess);
920 if (rc != Success)
921 return rc;
922
923 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
924
925 width = stuff->width;
926 height = stuff->height;
927 depth = stuff->depth;
928 if (!width || !height || !depth) {
929 client->errorValue = 0;
930 return BadValue;
931 }
932 if (width > 32767 || height > 32767)
933 return BadAlloc;
934
935 if (stuff->depth != 1) {
936 pDepth = pDraw->pScreen->allowedDepths;
937 for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
938 if (pDepth->depth == stuff->depth)
939 goto CreatePmap;
940 client->errorValue = stuff->depth;
941 return BadValue;
942 }
943
944 CreatePmap:
945 size = PixmapBytePad(width, depth) * height;
946 if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
947 if (size < width * height)
948 return BadAlloc;
949 }
950 /* thankfully, offset is unsigned */
951 if (stuff->offset + size < size)
952 return BadAlloc;
953
954 VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
955
956 if (!(newPix = malloc(sizeof(PanoramiXRes))))
957 return BadAlloc;
958
959 newPix->type = XRT_PIXMAP;
960 newPix->u.pix.shared = TRUE;
961 panoramix_setup_ids(newPix, client, stuff->pid);
962
963 result = Success;
964
965 FOR_NSCREENS(j) {
966 ShmScrPrivateRec *screen_priv;
967
968 pScreen = screenInfo.screens[j];
969
970 screen_priv = ShmGetScreenPriv(pScreen);
971 pMap = (*screen_priv->shmFuncs->CreatePixmap) (pScreen,
972 stuff->width,
973 stuff->height,
974 stuff->depth,
975 shmdesc->addr +
976 stuff->offset);
977
978 if (pMap) {
979 dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
980 shmdesc->refcnt++;
981 pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
982 pMap->drawable.id = newPix->info[j].id;
983 if (!AddResource(newPix->info[j].id, RT_PIXMAP, (pointer) pMap)) {
984 result = BadAlloc;
985 break;
986 }
987 }
988 else {
989 result = BadAlloc;
990 break;
991 }
992 }
993
994 if (result == BadAlloc) {
995 while (j--)
996 FreeResource(newPix->info[j].id, RT_NONE);
997 free(newPix);
998 }
999 else
1000 AddResource(stuff->pid, XRT_PIXMAP, newPix);
1001
1002 return result;
1003}
1004#endif
1005
1006static PixmapPtr
1007fbShmCreatePixmap(ScreenPtr pScreen,
1008 int width, int height, int depth, char *addr)
1009{
1010 PixmapPtr pPixmap;
1011
1012 pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0);
1013 if (!pPixmap)
1014 return NullPixmap;
1015
1016 if (!(*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth,
1017 BitsPerPixel(depth),
1018 PixmapBytePad(width, depth),
1019 (pointer) addr)) {
1020 (*pScreen->DestroyPixmap) (pPixmap);
1021 return NullPixmap;
1022 }
1023 return pPixmap;
1024}
1025
1026static int
1027ProcShmCreatePixmap(ClientPtr client)
1028{
1029 PixmapPtr pMap;
1030 DrawablePtr pDraw;
1031 DepthPtr pDepth;
1032 int i, rc;
1033 ShmDescPtr shmdesc;
1034 ShmScrPrivateRec *screen_priv;
1035
1036 REQUEST(xShmCreatePixmapReq);
1037 unsigned int width, height, depth;
1038 unsigned long size;
1039
1040 REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1041 client->errorValue = stuff->pid;
1042 if (!sharedPixmaps)
1043 return BadImplementation;
1044 LEGAL_NEW_RESOURCE(stuff->pid, client);
1045 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
1046 DixGetAttrAccess);
1047 if (rc != Success)
1048 return rc;
1049
1050 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
1051
1052 width = stuff->width;
1053 height = stuff->height;
1054 depth = stuff->depth;
1055 if (!width || !height || !depth) {
1056 client->errorValue = 0;
1057 return BadValue;
1058 }
1059 if (width > 32767 || height > 32767)
1060 return BadAlloc;
1061
1062 if (stuff->depth != 1) {
1063 pDepth = pDraw->pScreen->allowedDepths;
1064 for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
1065 if (pDepth->depth == stuff->depth)
1066 goto CreatePmap;
1067 client->errorValue = stuff->depth;
1068 return BadValue;
1069 }
1070
1071 CreatePmap:
1072 size = PixmapBytePad(width, depth) * height;
1073 if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
1074 if (size < width * height)
1075 return BadAlloc;
1076 }
1077 /* thankfully, offset is unsigned */
1078 if (stuff->offset + size < size)
1079 return BadAlloc;
1080
1081 VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
1082 screen_priv = ShmGetScreenPriv(pDraw->pScreen);
1083 pMap = (*screen_priv->shmFuncs->CreatePixmap) (pDraw->pScreen, stuff->width,
1084 stuff->height, stuff->depth,
1085 shmdesc->addr +
1086 stuff->offset);
1087 if (pMap) {
1088 rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP,
1089 pMap, RT_NONE, NULL, DixCreateAccess);
1090 if (rc != Success) {
1091 pDraw->pScreen->DestroyPixmap(pMap);
1092 return rc;
1093 }
1094 dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
1095 shmdesc->refcnt++;
1096 pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1097 pMap->drawable.id = stuff->pid;
1098 if (AddResource(stuff->pid, RT_PIXMAP, (pointer) pMap)) {
1099 return Success;
1100 }
1101 }
1102 return BadAlloc;
1103}
1104
1105#ifdef SHM_FD_PASSING
1106
1107static void
1108ShmBusfaultNotify(void *context)
1109{
1110 ShmDescPtr shmdesc = context;
1111
1112 ErrorF("shared memory 0x%x truncated by client\n",
1113 (unsigned int) shmdesc->resource);
1114 busfault_unregister(shmdesc->busfault);
1115 shmdesc->busfault = NULL;
1116 FreeResource (shmdesc->resource, RT_NONE);
1117}
1118
1119static int
1120ProcShmAttachFd(ClientPtr client)
1121{
1122 int fd;
1123 ShmDescPtr shmdesc;
1124 REQUEST(xShmAttachFdReq);
1125 struct stat statb;
1126
1127 SetReqFds(client, 1);
1128 REQUEST_SIZE_MATCH(xShmAttachFdReq);
1129 LEGAL_NEW_RESOURCE(stuff->shmseg, client);
1130 if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1131 client->errorValue = stuff->readOnly;
1132 return BadValue;
1133 }
1134 fd = ReadFdFromClient(client);
1135 if (fd < 0)
1136 return BadMatch;
1137
1138 if (fstat(fd, &statb) < 0 || statb.st_size == 0) {
1139 close(fd);
1140 return BadMatch;
1141 }
1142
1143 shmdesc = malloc(sizeof(ShmDescRec));
1144 if (!shmdesc) {
1145 close(fd);
1146 return BadAlloc;
1147 }
1148 shmdesc->is_fd = TRUE;
1149 shmdesc->addr = mmap(NULL, statb.st_size,
1150 stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1151 MAP_SHARED,
1152 fd, 0);
1153
1154 close(fd);
1155 if ((shmdesc->addr == ((char *) -1))) {
1156 free(shmdesc);
1157 return BadAccess;
1158 }
1159
1160 shmdesc->refcnt = 1;
1161 shmdesc->writable = !stuff->readOnly;
1162 shmdesc->size = statb.st_size;
1163 shmdesc->resource = stuff->shmseg;
1164
1165 shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1166 if (!shmdesc->busfault) {
1167 munmap(shmdesc->addr, shmdesc->size);
1168 free(shmdesc);
1169 return BadAlloc;
1170 }
1171
1172 shmdesc->next = Shmsegs;
1173 Shmsegs = shmdesc;
1174
1175 if (!AddResource(stuff->shmseg, ShmSegType, (pointer) shmdesc))
1176 return BadAlloc;
1177 return Success;
1178}
1179
1180static int
1181shm_tmpfile(void)
1182{
1183#ifdef SHMDIR
1184 int fd;
1185 int flags;
1186 char template[] = SHMDIR "/shmfd-XXXXXX";
1187#ifdef O_TMPFILE
1188 fd = open(SHMDIR, O_TMPFILE|O_RDWR|O_CLOEXEC|O_EXCL, 0666);
1189 if (fd >= 0) {
1190 ErrorF ("Using O_TMPFILE\n");
1191 return fd;
1192 }
1193 ErrorF ("Not using O_TMPFILE\n");
1194#endif
1195 fd = mkstemp(template);
1196 if (fd < 0)
1197 return -1;
1198 unlink(template);
1199 if (fcntl(fd, F_GETFD, &flags) >= 0) {
1200 flags |= FD_CLOEXEC;
1201 (void) fcntl(fd, F_SETFD, &flags);
1202 }
1203 return fd;
1204#else
1205 return -1;
1206#endif
1207}
1208
1209static int
1210ProcShmCreateSegment(ClientPtr client)
1211{
1212 int fd;
1213 ShmDescPtr shmdesc;
1214 REQUEST(xShmCreateSegmentReq);
1215 xShmCreateSegmentReply rep = {
1216 .type = X_Reply,
1217 .nfd = 1,
1218 .sequenceNumber = client->sequence,
1219 .length = 0,
1220 };
1221
1222 REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
1223 if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1224 client->errorValue = stuff->readOnly;
1225 return BadValue;
1226 }
1227 fd = shm_tmpfile();
1228 if (fd < 0)
1229 return BadAlloc;
1230 if (ftruncate(fd, stuff->size) < 0) {
1231 close(fd);
1232 return BadAlloc;
1233 }
1234 shmdesc = malloc(sizeof(ShmDescRec));
1235 if (!shmdesc) {
1236 close(fd);
1237 return BadAlloc;
1238 }
1239 shmdesc->is_fd = TRUE;
1240 shmdesc->addr = mmap(NULL, stuff->size,
1241 stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1242 MAP_SHARED,
1243 fd, 0);
1244
1245 if ((shmdesc->addr == ((char *) -1))) {
1246 close(fd);
1247 free(shmdesc);
1248 return BadAccess;
1249 }
1250
1251 shmdesc->refcnt = 1;
1252 shmdesc->writable = !stuff->readOnly;
1253 shmdesc->size = stuff->size;
1254
1255 shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1256 if (!shmdesc->busfault) {
1257 close(fd);
1258 munmap(shmdesc->addr, shmdesc->size);
1259 free(shmdesc);
1260 return BadAlloc;
1261 }
1262
1263 shmdesc->next = Shmsegs;
1264 Shmsegs = shmdesc;
1265
1266 if (!AddResource(stuff->shmseg, ShmSegType, (pointer) shmdesc)) {
1267 close(fd);
1268 return BadAlloc;
1269 }
1270
1271 if (WriteFdToClient(client, fd, TRUE) < 0) {
1272 FreeResource(stuff->shmseg, RT_NONE);
1273 close(fd);
1274 return BadAlloc;
1275 }
1276 WriteToClient(client, sizeof (xShmCreateSegmentReply), &rep);
1277 return Success;
1278}
1279#endif /* SHM_FD_PASSING */
1280
1281static int
1282ProcShmDispatch(ClientPtr client)
1283{
1284 REQUEST(xReq);
1285 switch (stuff->data) {
1286 case X_ShmQueryVersion:
1287 return ProcShmQueryVersion(client);
1288 case X_ShmAttach:
1289 return ProcShmAttach(client);
1290 case X_ShmDetach:
1291 return ProcShmDetach(client);
1292 case X_ShmPutImage:
1293#ifdef PANORAMIX
1294 if (!noPanoramiXExtension)
1295 return ProcPanoramiXShmPutImage(client);
1296#endif
1297 return ProcShmPutImage(client);
1298 case X_ShmGetImage:
1299#ifdef PANORAMIX
1300 if (!noPanoramiXExtension)
1301 return ProcPanoramiXShmGetImage(client);
1302#endif
1303 return ProcShmGetImage(client);
1304 case X_ShmCreatePixmap:
1305#ifdef PANORAMIX
1306 if (!noPanoramiXExtension)
1307 return ProcPanoramiXShmCreatePixmap(client);
1308#endif
1309 return ProcShmCreatePixmap(client);
1310#ifdef SHM_FD_PASSING
1311 case X_ShmAttachFd:
1312 return ProcShmAttachFd(client);
1313 case X_ShmCreateSegment:
1314 return ProcShmCreateSegment(client);
1315#endif
1316 default:
1317 return BadRequest;
1318 }
1319}
1320
1321static void
1322SShmCompletionEvent(xShmCompletionEvent * from, xShmCompletionEvent * to)
1323{
1324 to->type = from->type;
1325 cpswaps(from->sequenceNumber, to->sequenceNumber);
1326 cpswapl(from->drawable, to->drawable);
1327 cpswaps(from->minorEvent, to->minorEvent);
1328 to->majorEvent = from->majorEvent;
1329 cpswapl(from->shmseg, to->shmseg);
1330 cpswapl(from->offset, to->offset);
1331}
1332
1333static int
1334SProcShmQueryVersion(ClientPtr client)
1335{
1336 REQUEST(xShmQueryVersionReq);
1337
1338 swaps(&stuff->length);
1339 return ProcShmQueryVersion(client);
1340}
1341
1342static int
1343SProcShmAttach(ClientPtr client)
1344{
1345 REQUEST(xShmAttachReq);
1346 swaps(&stuff->length);
1347 REQUEST_SIZE_MATCH(xShmAttachReq);
1348 swapl(&stuff->shmseg);
1349 swapl(&stuff->shmid);
1350 return ProcShmAttach(client);
1351}
1352
1353static int
1354SProcShmDetach(ClientPtr client)
1355{
1356 REQUEST(xShmDetachReq);
1357 swaps(&stuff->length);
1358 REQUEST_SIZE_MATCH(xShmDetachReq);
1359 swapl(&stuff->shmseg);
1360 return ProcShmDetach(client);
1361}
1362
1363static int
1364SProcShmPutImage(ClientPtr client)
1365{
1366 REQUEST(xShmPutImageReq);
1367 swaps(&stuff->length);
1368 REQUEST_SIZE_MATCH(xShmPutImageReq);
1369 swapl(&stuff->drawable);
1370 swapl(&stuff->gc);
1371 swaps(&stuff->totalWidth);
1372 swaps(&stuff->totalHeight);
1373 swaps(&stuff->srcX);
1374 swaps(&stuff->srcY);
1375 swaps(&stuff->srcWidth);
1376 swaps(&stuff->srcHeight);
1377 swaps(&stuff->dstX);
1378 swaps(&stuff->dstY);
1379 swapl(&stuff->shmseg);
1380 swapl(&stuff->offset);
1381 return ProcShmPutImage(client);
1382}
1383
1384static int
1385SProcShmGetImage(ClientPtr client)
1386{
1387 REQUEST(xShmGetImageReq);
1388 swaps(&stuff->length);
1389 REQUEST_SIZE_MATCH(xShmGetImageReq);
1390 swapl(&stuff->drawable);
1391 swaps(&stuff->x);
1392 swaps(&stuff->y);
1393 swaps(&stuff->width);
1394 swaps(&stuff->height);
1395 swapl(&stuff->planeMask);
1396 swapl(&stuff->shmseg);
1397 swapl(&stuff->offset);
1398 return ProcShmGetImage(client);
1399}
1400
1401static int
1402SProcShmCreatePixmap(ClientPtr client)
1403{
1404 REQUEST(xShmCreatePixmapReq);
1405 swaps(&stuff->length);
1406 REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1407 swapl(&stuff->pid);
1408 swapl(&stuff->drawable);
1409 swaps(&stuff->width);
1410 swaps(&stuff->height);
1411 swapl(&stuff->shmseg);
1412 swapl(&stuff->offset);
1413 return ProcShmCreatePixmap(client);
1414}
1415
1416#ifdef SHM_FD_PASSING
1417static int
1418SProcShmAttachFd(ClientPtr client)
1419{
1420 REQUEST(xShmAttachFdReq);
1421 SetReqFds(client, 1);
1422 swaps(&stuff->length);
1423 REQUEST_SIZE_MATCH(xShmAttachFdReq);
1424 swapl(&stuff->shmseg);
1425 return ProcShmAttachFd(client);
1426}
1427
1428static int
1429SProcShmCreateSegment(ClientPtr client)
1430{
1431 REQUEST(xShmCreateSegmentReq);
1432 swaps(&stuff->length);
1433 REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
1434 swapl(&stuff->shmseg);
1435 swapl(&stuff->size);
1436 return ProcShmCreateSegment(client);
1437}
1438#endif /* SHM_FD_PASSING */
1439
1440static int
1441SProcShmDispatch(ClientPtr client)
1442{
1443 REQUEST(xReq);
1444 switch (stuff->data) {
1445 case X_ShmQueryVersion:
1446 return SProcShmQueryVersion(client);
1447 case X_ShmAttach:
1448 return SProcShmAttach(client);
1449 case X_ShmDetach:
1450 return SProcShmDetach(client);
1451 case X_ShmPutImage:
1452 return SProcShmPutImage(client);
1453 case X_ShmGetImage:
1454 return SProcShmGetImage(client);
1455 case X_ShmCreatePixmap:
1456 return SProcShmCreatePixmap(client);
1457#ifdef SHM_FD_PASSING
1458 case X_ShmAttachFd:
1459 return SProcShmAttachFd(client);
1460 case X_ShmCreateSegment:
1461 return SProcShmCreateSegment(client);
1462#endif
1463 default:
1464 return BadRequest;
1465 }
1466}
1467
1468void
1469ShmExtensionInit(void)
1470{
1471 ExtensionEntry *extEntry;
1472 int i;
1473
1474#ifdef MUST_CHECK_FOR_SHM_SYSCALL
1475 if (!CheckForShmSyscall()) {
1476 ErrorF("MIT-SHM extension disabled due to lack of kernel support\n");
1477 return;
1478 }
1479#endif
1480
1481 if (!ShmRegisterPrivates())
1482 return;
1483
1484 sharedPixmaps = xFalse;
1485 {
1486 sharedPixmaps = xTrue;
1487 for (i = 0; i < screenInfo.numScreens; i++) {
1488 ShmScrPrivateRec *screen_priv =
1489 ShmInitScreenPriv(screenInfo.screens[i]);
1490 if (!screen_priv->shmFuncs)
1491 screen_priv->shmFuncs = &miFuncs;
1492 if (!screen_priv->shmFuncs->CreatePixmap)
1493 sharedPixmaps = xFalse;
1494 }
1495 if (sharedPixmaps)
1496 for (i = 0; i < screenInfo.numScreens; i++) {
1497 ShmScrPrivateRec *screen_priv =
1498 ShmGetScreenPriv(screenInfo.screens[i]);
1499 screen_priv->destroyPixmap =
1500 screenInfo.screens[i]->DestroyPixmap;
1501 screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap;
1502 }
1503 }
1504 ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg");
1505 if (ShmSegType &&
1506 (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors,
1507 ProcShmDispatch, SProcShmDispatch,
1508 ShmResetProc, StandardMinorOpcode))) {
1509 ShmReqCode = (unsigned char) extEntry->base;
1510 ShmCompletionCode = extEntry->eventBase;
1511 BadShmSegCode = extEntry->errorBase;
1512 SetResourceTypeErrorValue(ShmSegType, BadShmSegCode);
1513 EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent;
1514 }
1515}