shm.c revision 05b261ec
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
30#define SHM
31
32#ifdef HAVE_DIX_CONFIG_H
33#include <dix-config.h>
34#endif
35
36#include <sys/types.h>
37#ifndef Lynx
38#include <sys/ipc.h>
39#include <sys/shm.h>
40#else
41#include <ipc.h>
42#include <shm.h>
43#endif
44#include <unistd.h>
45#include <sys/stat.h>
46#define NEED_REPLIES
47#define NEED_EVENTS
48#include <X11/X.h>
49#include <X11/Xproto.h>
50#include "misc.h"
51#include "os.h"
52#include "dixstruct.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#define _XSHM_SERVER_
61#include <X11/extensions/shmstr.h>
62#include <X11/Xfuncproto.h>
63
64#ifdef PANORAMIX
65#include "panoramiX.h"
66#include "panoramiXsrv.h"
67#endif
68
69#include "modinit.h"
70
71typedef struct _ShmDesc {
72    struct _ShmDesc *next;
73    int shmid;
74    int refcnt;
75    char *addr;
76    Bool writable;
77    unsigned long size;
78} ShmDescRec, *ShmDescPtr;
79
80static void miShmPutImage(XSHM_PUT_IMAGE_ARGS);
81static void fbShmPutImage(XSHM_PUT_IMAGE_ARGS);
82static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS);
83static int ShmDetachSegment(
84    pointer		/* value */,
85    XID			/* shmseg */
86    );
87static void ShmResetProc(
88    ExtensionEntry *	/* extEntry */
89    );
90static void SShmCompletionEvent(
91    xShmCompletionEvent * /* from */,
92    xShmCompletionEvent * /* to */
93    );
94
95static Bool ShmDestroyPixmap (PixmapPtr pPixmap);
96
97static DISPATCH_PROC(ProcShmAttach);
98static DISPATCH_PROC(ProcShmCreatePixmap);
99static DISPATCH_PROC(ProcShmDetach);
100static DISPATCH_PROC(ProcShmDispatch);
101static DISPATCH_PROC(ProcShmGetImage);
102static DISPATCH_PROC(ProcShmPutImage);
103static DISPATCH_PROC(ProcShmQueryVersion);
104static DISPATCH_PROC(SProcShmAttach);
105static DISPATCH_PROC(SProcShmCreatePixmap);
106static DISPATCH_PROC(SProcShmDetach);
107static DISPATCH_PROC(SProcShmDispatch);
108static DISPATCH_PROC(SProcShmGetImage);
109static DISPATCH_PROC(SProcShmPutImage);
110static DISPATCH_PROC(SProcShmQueryVersion);
111
112static unsigned char ShmReqCode;
113_X_EXPORT int ShmCompletionCode;
114_X_EXPORT int BadShmSegCode;
115_X_EXPORT RESTYPE ShmSegType;
116static ShmDescPtr Shmsegs;
117static Bool sharedPixmaps;
118static int pixmapFormat;
119static int shmPixFormat[MAXSCREENS];
120static ShmFuncsPtr shmFuncs[MAXSCREENS];
121static DestroyPixmapProcPtr destroyPixmap[MAXSCREENS];
122static int  shmPixmapPrivate;
123static ShmFuncs miFuncs = {NULL, miShmPutImage};
124static ShmFuncs fbFuncs = {fbShmCreatePixmap, fbShmPutImage};
125
126#define VERIFY_SHMSEG(shmseg,shmdesc,client) \
127{ \
128    shmdesc = (ShmDescPtr)LookupIDByType(shmseg, ShmSegType); \
129    if (!shmdesc) \
130    { \
131	client->errorValue = shmseg; \
132	return BadShmSegCode; \
133    } \
134}
135
136#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \
137{ \
138    VERIFY_SHMSEG(shmseg, shmdesc, client); \
139    if ((offset & 3) || (offset > shmdesc->size)) \
140    { \
141	client->errorValue = offset; \
142	return BadValue; \
143    } \
144    if (needwrite && !shmdesc->writable) \
145	return BadAccess; \
146}
147
148#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \
149{ \
150    if ((offset + len) > shmdesc->size) \
151    { \
152	return BadAccess; \
153    } \
154}
155
156
157#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
158#include <sys/signal.h>
159
160static Bool badSysCall = FALSE;
161
162static void
163SigSysHandler(signo)
164int signo;
165{
166    badSysCall = TRUE;
167}
168
169static Bool CheckForShmSyscall()
170{
171    void (*oldHandler)();
172    int shmid = -1;
173
174    /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
175    oldHandler = signal(SIGSYS, SigSysHandler);
176
177    badSysCall = FALSE;
178    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
179
180    if (shmid != -1)
181    {
182        /* Successful allocation - clean up */
183	shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL);
184    }
185    else
186    {
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
198void
199ShmExtensionInit(INITARGS)
200{
201    ExtensionEntry *extEntry;
202    int i;
203
204#ifdef MUST_CHECK_FOR_SHM_SYSCALL
205    if (!CheckForShmSyscall())
206    {
207	ErrorF("MIT-SHM extension disabled due to lack of kernel support\n");
208	return;
209    }
210#endif
211
212    sharedPixmaps = xFalse;
213    pixmapFormat = 0;
214    {
215      sharedPixmaps = xTrue;
216      pixmapFormat = shmPixFormat[0];
217      for (i = 0; i < screenInfo.numScreens; i++)
218      {
219	if (!shmFuncs[i])
220	    shmFuncs[i] = &miFuncs;
221	if (!shmFuncs[i]->CreatePixmap)
222	    sharedPixmaps = xFalse;
223	if (shmPixFormat[i] && (shmPixFormat[i] != pixmapFormat))
224	{
225	    sharedPixmaps = xFalse;
226	    pixmapFormat = 0;
227	}
228      }
229      if (!pixmapFormat)
230	pixmapFormat = ZPixmap;
231      if (sharedPixmaps)
232      {
233	for (i = 0; i < screenInfo.numScreens; i++)
234	{
235	    destroyPixmap[i] = screenInfo.screens[i]->DestroyPixmap;
236	    screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap;
237	}
238	shmPixmapPrivate = AllocatePixmapPrivateIndex();
239	for (i = 0; i < screenInfo.numScreens; i++)
240	{
241	    if (!AllocatePixmapPrivate(screenInfo.screens[i],
242				       shmPixmapPrivate, 0))
243		return;
244	}
245      }
246    }
247    ShmSegType = CreateNewResourceType(ShmDetachSegment);
248    if (ShmSegType &&
249	(extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors,
250				 ProcShmDispatch, SProcShmDispatch,
251				 ShmResetProc, StandardMinorOpcode)))
252    {
253	ShmReqCode = (unsigned char)extEntry->base;
254	ShmCompletionCode = extEntry->eventBase;
255	BadShmSegCode = extEntry->errorBase;
256	EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent;
257    }
258}
259
260/*ARGSUSED*/
261static void
262ShmResetProc (extEntry)
263ExtensionEntry	*extEntry;
264{
265    int i;
266
267    for (i = 0; i < MAXSCREENS; i++)
268    {
269	shmFuncs[i] = (ShmFuncsPtr)NULL;
270	shmPixFormat[i] = 0;
271    }
272}
273
274void
275ShmRegisterFuncs(
276    ScreenPtr pScreen,
277    ShmFuncsPtr funcs)
278{
279    shmFuncs[pScreen->myNum] = funcs;
280}
281
282void
283ShmSetPixmapFormat(
284    ScreenPtr pScreen,
285    int format)
286{
287    shmPixFormat[pScreen->myNum] = format;
288}
289
290static Bool
291ShmDestroyPixmap (PixmapPtr pPixmap)
292{
293    ScreenPtr	    pScreen = pPixmap->drawable.pScreen;
294    Bool	    ret;
295    if (pPixmap->refcnt == 1)
296    {
297	ShmDescPtr  shmdesc;
298	shmdesc = (ShmDescPtr) pPixmap->devPrivates[shmPixmapPrivate].ptr;
299	if (shmdesc)
300	    ShmDetachSegment ((pointer) shmdesc, pPixmap->drawable.id);
301    }
302
303    pScreen->DestroyPixmap = destroyPixmap[pScreen->myNum];
304    ret = (*pScreen->DestroyPixmap) (pPixmap);
305    destroyPixmap[pScreen->myNum] = pScreen->DestroyPixmap;
306    pScreen->DestroyPixmap = ShmDestroyPixmap;
307    return ret;
308}
309
310void
311ShmRegisterFbFuncs(pScreen)
312    ScreenPtr pScreen;
313{
314    shmFuncs[pScreen->myNum] = &fbFuncs;
315}
316
317static int
318ProcShmQueryVersion(client)
319    register ClientPtr client;
320{
321    xShmQueryVersionReply rep;
322    register int n;
323
324    REQUEST_SIZE_MATCH(xShmQueryVersionReq);
325    rep.type = X_Reply;
326    rep.length = 0;
327    rep.sequenceNumber = client->sequence;
328    rep.sharedPixmaps = sharedPixmaps;
329    rep.pixmapFormat = pixmapFormat;
330    rep.majorVersion = SHM_MAJOR_VERSION;
331    rep.minorVersion = SHM_MINOR_VERSION;
332    rep.uid = geteuid();
333    rep.gid = getegid();
334    if (client->swapped) {
335    	swaps(&rep.sequenceNumber, n);
336    	swapl(&rep.length, n);
337	swaps(&rep.majorVersion, n);
338	swaps(&rep.minorVersion, n);
339	swaps(&rep.uid, n);
340	swaps(&rep.gid, n);
341    }
342    WriteToClient(client, sizeof(xShmQueryVersionReply), (char *)&rep);
343    return (client->noClientException);
344}
345
346/*
347 * Simulate the access() system call for a shared memory segement,
348 * using the credentials from the client if available
349 */
350static int
351shm_access(ClientPtr client, struct ipc_perm *perm, int readonly)
352{
353    int uid, gid;
354    mode_t mask;
355
356    if (LocalClientCred(client, &uid, &gid) != -1) {
357
358	/* User id 0 always gets access */
359	if (uid == 0) {
360	    return 0;
361	}
362	/* Check the owner */
363	if (perm->uid == uid || perm->cuid == uid) {
364	    mask = S_IRUSR;
365	    if (!readonly) {
366		mask |= S_IWUSR;
367	    }
368	    return (perm->mode & mask) == mask ? 0 : -1;
369	}
370	/* Check the group */
371	if (perm->gid == gid || perm->cgid == gid) {
372	    mask = S_IRGRP;
373	    if (!readonly) {
374		mask |= S_IWGRP;
375	    }
376	    return (perm->mode & mask) == mask ? 0 : -1;
377	}
378    }
379    /* Otherwise, check everyone else */
380    mask = S_IROTH;
381    if (!readonly) {
382	mask |= S_IWOTH;
383    }
384    return (perm->mode & mask) == mask ? 0 : -1;
385}
386
387static int
388ProcShmAttach(client)
389    register ClientPtr client;
390{
391    struct shmid_ds buf;
392    ShmDescPtr shmdesc;
393    REQUEST(xShmAttachReq);
394
395    REQUEST_SIZE_MATCH(xShmAttachReq);
396    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
397    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse))
398    {
399	client->errorValue = stuff->readOnly;
400        return(BadValue);
401    }
402    for (shmdesc = Shmsegs;
403	 shmdesc && (shmdesc->shmid != stuff->shmid);
404	 shmdesc = shmdesc->next)
405	;
406    if (shmdesc)
407    {
408	if (!stuff->readOnly && !shmdesc->writable)
409	    return BadAccess;
410	shmdesc->refcnt++;
411    }
412    else
413    {
414	shmdesc = (ShmDescPtr) xalloc(sizeof(ShmDescRec));
415	if (!shmdesc)
416	    return BadAlloc;
417	shmdesc->addr = shmat(stuff->shmid, 0,
418			      stuff->readOnly ? SHM_RDONLY : 0);
419	if ((shmdesc->addr == ((char *)-1)) ||
420	    shmctl(stuff->shmid, IPC_STAT, &buf))
421	{
422	    xfree(shmdesc);
423	    return BadAccess;
424	}
425
426	/* The attach was performed with root privs. We must
427	 * do manual checking of access rights for the credentials
428	 * of the client */
429
430	if (shm_access(client, &(buf.shm_perm), stuff->readOnly) == -1) {
431	    shmdt(shmdesc->addr);
432	    xfree(shmdesc);
433	    return BadAccess;
434	}
435
436	shmdesc->shmid = stuff->shmid;
437	shmdesc->refcnt = 1;
438	shmdesc->writable = !stuff->readOnly;
439	shmdesc->size = buf.shm_segsz;
440	shmdesc->next = Shmsegs;
441	Shmsegs = shmdesc;
442    }
443    if (!AddResource(stuff->shmseg, ShmSegType, (pointer)shmdesc))
444	return BadAlloc;
445    return(client->noClientException);
446}
447
448/*ARGSUSED*/
449static int
450ShmDetachSegment(value, shmseg)
451    pointer value; /* must conform to DeleteType */
452    XID shmseg;
453{
454    ShmDescPtr shmdesc = (ShmDescPtr)value;
455    ShmDescPtr *prev;
456
457    if (--shmdesc->refcnt)
458	return TRUE;
459    shmdt(shmdesc->addr);
460    for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next)
461	;
462    *prev = shmdesc->next;
463    xfree(shmdesc);
464    return Success;
465}
466
467static int
468ProcShmDetach(client)
469    register ClientPtr client;
470{
471    ShmDescPtr shmdesc;
472    REQUEST(xShmDetachReq);
473
474    REQUEST_SIZE_MATCH(xShmDetachReq);
475    VERIFY_SHMSEG(stuff->shmseg, shmdesc, client);
476    FreeResource(stuff->shmseg, RT_NONE);
477    return(client->noClientException);
478}
479
480static void
481miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data)
482    DrawablePtr dst;
483    GCPtr	pGC;
484    int		depth, w, h, sx, sy, sw, sh, dx, dy;
485    unsigned int format;
486    char 	*data;
487{
488    PixmapPtr pmap;
489    GCPtr putGC;
490
491    putGC = GetScratchGC(depth, dst->pScreen);
492    if (!putGC)
493	return;
494    pmap = (*dst->pScreen->CreatePixmap)(dst->pScreen, sw, sh, depth);
495    if (!pmap)
496    {
497	FreeScratchGC(putGC);
498	return;
499    }
500    ValidateGC((DrawablePtr)pmap, putGC);
501    (*putGC->ops->PutImage)((DrawablePtr)pmap, putGC, depth, -sx, -sy, w, h, 0,
502			    (format == XYPixmap) ? XYPixmap : ZPixmap, data);
503    FreeScratchGC(putGC);
504    if (format == XYBitmap)
505	(void)(*pGC->ops->CopyPlane)((DrawablePtr)pmap, dst, pGC, 0, 0, sw, sh,
506				     dx, dy, 1L);
507    else
508	(void)(*pGC->ops->CopyArea)((DrawablePtr)pmap, dst, pGC, 0, 0, sw, sh,
509				    dx, dy);
510    (*pmap->drawable.pScreen->DestroyPixmap)(pmap);
511}
512
513static void
514fbShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data)
515    DrawablePtr dst;
516    GCPtr	pGC;
517    int		depth, w, h, sx, sy, sw, sh, dx, dy;
518    unsigned int format;
519    char 	*data;
520{
521    if ((format == ZPixmap) || (depth == 1))
522    {
523	PixmapPtr pPixmap;
524
525	pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth,
526		BitsPerPixel(depth), PixmapBytePad(w, depth), (pointer)data);
527	if (!pPixmap)
528	    return;
529	if (format == XYBitmap)
530	    (void)(*pGC->ops->CopyPlane)((DrawablePtr)pPixmap, dst, pGC,
531					 sx, sy, sw, sh, dx, dy, 1L);
532	else
533	    (void)(*pGC->ops->CopyArea)((DrawablePtr)pPixmap, dst, pGC,
534					sx, sy, sw, sh, dx, dy);
535	FreeScratchPixmapHeader(pPixmap);
536    }
537    else
538	miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy,
539		      data);
540}
541
542
543#ifdef PANORAMIX
544static int
545ProcPanoramiXShmPutImage(register ClientPtr client)
546{
547    int			 j, result = 0, orig_x, orig_y;
548    PanoramiXRes	*draw, *gc;
549    Bool		 sendEvent, isRoot;
550
551    REQUEST(xShmPutImageReq);
552    REQUEST_SIZE_MATCH(xShmPutImageReq);
553
554    if(!(draw = (PanoramiXRes *)SecurityLookupIDByClass(
555                client, stuff->drawable, XRC_DRAWABLE, DixWriteAccess)))
556        return BadDrawable;
557
558    if(!(gc = (PanoramiXRes *)SecurityLookupIDByType(
559                client, stuff->gc, XRT_GC, DixReadAccess)))
560        return BadGC;
561
562    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
563
564    orig_x = stuff->dstX;
565    orig_y = stuff->dstY;
566    sendEvent = stuff->sendEvent;
567    stuff->sendEvent = 0;
568    FOR_NSCREENS(j) {
569	if(!j) stuff->sendEvent = sendEvent;
570	stuff->drawable = draw->info[j].id;
571	stuff->gc = gc->info[j].id;
572	if (isRoot) {
573	    stuff->dstX = orig_x - panoramiXdataPtr[j].x;
574	    stuff->dstY = orig_y - panoramiXdataPtr[j].y;
575	}
576	result = ProcShmPutImage(client);
577	if(result != client->noClientException) break;
578    }
579    return(result);
580}
581
582static int
583ProcPanoramiXShmGetImage(ClientPtr client)
584{
585    PanoramiXRes	*draw;
586    DrawablePtr 	drawables[MAXSCREENS];
587    DrawablePtr 	pDraw;
588    xShmGetImageReply	xgi;
589    ShmDescPtr		shmdesc;
590    int         	i, x, y, w, h, format, rc;
591    Mask		plane = 0, planemask;
592    long		lenPer = 0, length, widthBytesLine;
593    Bool		isRoot;
594
595    REQUEST(xShmGetImageReq);
596
597    REQUEST_SIZE_MATCH(xShmGetImageReq);
598
599    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
600	client->errorValue = stuff->format;
601        return(BadValue);
602    }
603
604    if(!(draw = (PanoramiXRes *)SecurityLookupIDByClass(
605		client, stuff->drawable, XRC_DRAWABLE, DixWriteAccess)))
606	return BadDrawable;
607
608    if (draw->type == XRT_PIXMAP)
609	return ProcShmGetImage(client);
610
611    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0,
612			   DixUnknownAccess);
613    if (rc != Success)
614	return rc;
615
616    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
617
618    x = stuff->x;
619    y = stuff->y;
620    w = stuff->width;
621    h = stuff->height;
622    format = stuff->format;
623    planemask = stuff->planeMask;
624
625    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
626
627    if(isRoot) {
628      if( /* check for being onscreen */
629	x < 0 || x + w > PanoramiXPixWidth ||
630	y < 0 || y + h > PanoramiXPixHeight )
631	    return(BadMatch);
632    } else {
633      if( /* check for being onscreen */
634	panoramiXdataPtr[0].x + pDraw->x + x < 0 ||
635	panoramiXdataPtr[0].x + pDraw->x + x + w > PanoramiXPixWidth ||
636        panoramiXdataPtr[0].y + pDraw->y + y < 0 ||
637	panoramiXdataPtr[0].y + pDraw->y + y + h > PanoramiXPixHeight ||
638	 /* check for being inside of border */
639       	x < - wBorderWidth((WindowPtr)pDraw) ||
640	x + w > wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width ||
641	y < -wBorderWidth((WindowPtr)pDraw) ||
642	y + h > wBorderWidth ((WindowPtr)pDraw) + (int)pDraw->height)
643	    return(BadMatch);
644    }
645
646    drawables[0] = pDraw;
647    for(i = 1; i < PanoramiXNumScreens; i++) {
648	rc = dixLookupDrawable(drawables+i, draw->info[i].id, client, 0,
649			       DixUnknownAccess);
650	if (rc != Success)
651	    return rc;
652    }
653
654    xgi.visual = wVisual(((WindowPtr)pDraw));
655    xgi.type = X_Reply;
656    xgi.length = 0;
657    xgi.sequenceNumber = client->sequence;
658    xgi.depth = pDraw->depth;
659
660    if(format == ZPixmap) {
661	widthBytesLine = PixmapBytePad(w, pDraw->depth);
662	length = widthBytesLine * h;
663    } else {
664	widthBytesLine = PixmapBytePad(w, 1);
665	lenPer = widthBytesLine * h;
666	plane = ((Mask)1) << (pDraw->depth - 1);
667	length = lenPer * Ones(planemask & (plane | (plane - 1)));
668    }
669
670    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
671    xgi.size = length;
672
673    if (length == 0) {/* nothing to do */ }
674    else if (format == ZPixmap) {
675	    XineramaGetImageData(drawables, x, y, w, h, format, planemask,
676					shmdesc->addr + stuff->offset,
677					widthBytesLine, isRoot);
678    } else {
679
680	length = stuff->offset;
681        for (; plane; plane >>= 1) {
682	    if (planemask & plane) {
683		XineramaGetImageData(drawables, x, y, w, h,
684				     format, plane, shmdesc->addr + length,
685				     widthBytesLine, isRoot);
686		length += lenPer;
687	    }
688	}
689    }
690
691    if (client->swapped) {
692	register int n;
693    	swaps(&xgi.sequenceNumber, n);
694    	swapl(&xgi.length, n);
695	swapl(&xgi.visual, n);
696	swapl(&xgi.size, n);
697    }
698    WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi);
699
700    return(client->noClientException);
701}
702
703static int
704ProcPanoramiXShmCreatePixmap(
705    register ClientPtr client)
706{
707    ScreenPtr pScreen = NULL;
708    PixmapPtr pMap = NULL;
709    DrawablePtr pDraw;
710    DepthPtr pDepth;
711    int i, j, result, rc;
712    ShmDescPtr shmdesc;
713    REQUEST(xShmCreatePixmapReq);
714    unsigned int width, height, depth;
715    unsigned long size;
716    PanoramiXRes *newPix;
717
718    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
719    client->errorValue = stuff->pid;
720    if (!sharedPixmaps)
721	return BadImplementation;
722    LEGAL_NEW_RESOURCE(stuff->pid, client);
723    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
724			   DixUnknownAccess);
725    if (rc != Success)
726	return rc;
727
728    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
729
730    width = stuff->width;
731    height = stuff->height;
732    depth = stuff->depth;
733    if (!width || !height || !depth)
734    {
735	client->errorValue = 0;
736        return BadValue;
737    }
738    if (width > 32767 || height > 32767)
739        return BadAlloc;
740
741    if (stuff->depth != 1)
742    {
743        pDepth = pDraw->pScreen->allowedDepths;
744        for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++)
745	   if (pDepth->depth == stuff->depth)
746               goto CreatePmap;
747	client->errorValue = stuff->depth;
748        return BadValue;
749    }
750
751CreatePmap:
752    size = PixmapBytePad(width, depth) * height;
753    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
754        if (size < width * height)
755            return BadAlloc;
756    }
757    /* thankfully, offset is unsigned */
758    if (stuff->offset + size < size)
759	return BadAlloc;
760
761    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
762
763    if(!(newPix = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes))))
764	return BadAlloc;
765
766    newPix->type = XRT_PIXMAP;
767    newPix->u.pix.shared = TRUE;
768    newPix->info[0].id = stuff->pid;
769    for(j = 1; j < PanoramiXNumScreens; j++)
770	newPix->info[j].id = FakeClientID(client->index);
771
772    result = (client->noClientException);
773
774    FOR_NSCREENS(j) {
775	pScreen = screenInfo.screens[j];
776
777	pMap = (*shmFuncs[j]->CreatePixmap)(pScreen,
778				stuff->width, stuff->height, stuff->depth,
779				shmdesc->addr + stuff->offset);
780
781	if (pMap) {
782            pMap->devPrivates[shmPixmapPrivate].ptr = (pointer) shmdesc;
783            shmdesc->refcnt++;
784	    pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
785	    pMap->drawable.id = newPix->info[j].id;
786	    if (!AddResource(newPix->info[j].id, RT_PIXMAP, (pointer)pMap)) {
787		(*pScreen->DestroyPixmap)(pMap);
788		result = BadAlloc;
789		break;
790	    }
791	} else {
792	   result = BadAlloc;
793	   break;
794	}
795    }
796
797    if(result == BadAlloc) {
798	while(j--) {
799	    (*pScreen->DestroyPixmap)(pMap);
800	    FreeResource(newPix->info[j].id, RT_NONE);
801	}
802	xfree(newPix);
803    } else
804	AddResource(stuff->pid, XRT_PIXMAP, newPix);
805
806    return result;
807}
808
809#endif
810
811static int
812ProcShmPutImage(client)
813    register ClientPtr client;
814{
815    GCPtr pGC;
816    DrawablePtr pDraw;
817    long length;
818    ShmDescPtr shmdesc;
819    REQUEST(xShmPutImageReq);
820
821    REQUEST_SIZE_MATCH(xShmPutImageReq);
822    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
823    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client);
824    if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse))
825	return BadValue;
826    if (stuff->format == XYBitmap)
827    {
828        if (stuff->depth != 1)
829            return BadMatch;
830        length = PixmapBytePad(stuff->totalWidth, 1);
831    }
832    else if (stuff->format == XYPixmap)
833    {
834        if (pDraw->depth != stuff->depth)
835            return BadMatch;
836        length = PixmapBytePad(stuff->totalWidth, 1);
837	length *= stuff->depth;
838    }
839    else if (stuff->format == ZPixmap)
840    {
841        if (pDraw->depth != stuff->depth)
842            return BadMatch;
843        length = PixmapBytePad(stuff->totalWidth, stuff->depth);
844    }
845    else
846    {
847	client->errorValue = stuff->format;
848        return BadValue;
849    }
850
851    /*
852     * There's a potential integer overflow in this check:
853     * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight,
854     *                client);
855     * the version below ought to avoid it
856     */
857    if (stuff->totalHeight != 0 &&
858	length > (shmdesc->size - stuff->offset)/stuff->totalHeight) {
859	client->errorValue = stuff->totalWidth;
860	return BadValue;
861    }
862    if (stuff->srcX > stuff->totalWidth)
863    {
864	client->errorValue = stuff->srcX;
865	return BadValue;
866    }
867    if (stuff->srcY > stuff->totalHeight)
868    {
869	client->errorValue = stuff->srcY;
870	return BadValue;
871    }
872    if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth)
873    {
874	client->errorValue = stuff->srcWidth;
875	return BadValue;
876    }
877    if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight)
878    {
879	client->errorValue = stuff->srcHeight;
880	return BadValue;
881    }
882
883    if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) ||
884	 ((stuff->format != ZPixmap) &&
885	  (stuff->srcX < screenInfo.bitmapScanlinePad) &&
886	  ((stuff->format == XYBitmap) ||
887	   ((stuff->srcY == 0) &&
888	    (stuff->srcHeight == stuff->totalHeight))))) &&
889	((stuff->srcX + stuff->srcWidth) == stuff->totalWidth))
890	(*pGC->ops->PutImage) (pDraw, pGC, stuff->depth,
891			       stuff->dstX, stuff->dstY,
892			       stuff->totalWidth, stuff->srcHeight,
893			       stuff->srcX, stuff->format,
894			       shmdesc->addr + stuff->offset +
895			       (stuff->srcY * length));
896    else
897	(*shmFuncs[pDraw->pScreen->myNum]->PutImage)(
898			       pDraw, pGC, stuff->depth, stuff->format,
899			       stuff->totalWidth, stuff->totalHeight,
900			       stuff->srcX, stuff->srcY,
901			       stuff->srcWidth, stuff->srcHeight,
902			       stuff->dstX, stuff->dstY,
903                               shmdesc->addr + stuff->offset);
904
905    if (stuff->sendEvent)
906    {
907	xShmCompletionEvent ev;
908
909	ev.type = ShmCompletionCode;
910	ev.drawable = stuff->drawable;
911	ev.sequenceNumber = client->sequence;
912	ev.minorEvent = X_ShmPutImage;
913	ev.majorEvent = ShmReqCode;
914	ev.shmseg = stuff->shmseg;
915	ev.offset = stuff->offset;
916	WriteEventsToClient(client, 1, (xEvent *) &ev);
917    }
918
919    return (client->noClientException);
920}
921
922
923
924static int
925ProcShmGetImage(client)
926    register ClientPtr client;
927{
928    DrawablePtr		pDraw;
929    long		lenPer = 0, length;
930    Mask		plane = 0;
931    xShmGetImageReply	xgi;
932    ShmDescPtr		shmdesc;
933    int			n, rc;
934
935    REQUEST(xShmGetImageReq);
936
937    REQUEST_SIZE_MATCH(xShmGetImageReq);
938    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap))
939    {
940	client->errorValue = stuff->format;
941        return(BadValue);
942    }
943    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0,
944			   DixUnknownAccess);
945    if (rc != Success)
946	return rc;
947    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
948    if (pDraw->type == DRAWABLE_WINDOW)
949    {
950      if( /* check for being viewable */
951	 !((WindowPtr) pDraw)->realized ||
952	  /* check for being on screen */
953         pDraw->x + stuff->x < 0 ||
954 	 pDraw->x + stuff->x + (int)stuff->width > pDraw->pScreen->width ||
955         pDraw->y + stuff->y < 0 ||
956         pDraw->y + stuff->y + (int)stuff->height > pDraw->pScreen->height ||
957          /* check for being inside of border */
958         stuff->x < - wBorderWidth((WindowPtr)pDraw) ||
959         stuff->x + (int)stuff->width >
960		wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width ||
961         stuff->y < -wBorderWidth((WindowPtr)pDraw) ||
962         stuff->y + (int)stuff->height >
963		wBorderWidth((WindowPtr)pDraw) + (int)pDraw->height
964        )
965	    return(BadMatch);
966	xgi.visual = wVisual(((WindowPtr)pDraw));
967    }
968    else
969    {
970	if (stuff->x < 0 ||
971	    stuff->x+(int)stuff->width > pDraw->width ||
972	    stuff->y < 0 ||
973	    stuff->y+(int)stuff->height > pDraw->height
974	    )
975	    return(BadMatch);
976	xgi.visual = None;
977    }
978    xgi.type = X_Reply;
979    xgi.length = 0;
980    xgi.sequenceNumber = client->sequence;
981    xgi.depth = pDraw->depth;
982    if(stuff->format == ZPixmap)
983    {
984	length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height;
985    }
986    else
987    {
988	lenPer = PixmapBytePad(stuff->width, 1) * stuff->height;
989	plane = ((Mask)1) << (pDraw->depth - 1);
990	/* only planes asked for */
991	length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
992    }
993
994    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
995    xgi.size = length;
996
997    if (length == 0)
998    {
999	/* nothing to do */
1000    }
1001    else if (stuff->format == ZPixmap)
1002    {
1003	(*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y,
1004				    stuff->width, stuff->height,
1005				    stuff->format, stuff->planeMask,
1006				    shmdesc->addr + stuff->offset);
1007    }
1008    else
1009    {
1010
1011	length = stuff->offset;
1012        for (; plane; plane >>= 1)
1013	{
1014	    if (stuff->planeMask & plane)
1015	    {
1016		(*pDraw->pScreen->GetImage)(pDraw,
1017					    stuff->x, stuff->y,
1018					    stuff->width, stuff->height,
1019					    stuff->format, plane,
1020					    shmdesc->addr + length);
1021		length += lenPer;
1022	    }
1023	}
1024    }
1025
1026    if (client->swapped) {
1027    	swaps(&xgi.sequenceNumber, n);
1028    	swapl(&xgi.length, n);
1029	swapl(&xgi.visual, n);
1030	swapl(&xgi.size, n);
1031    }
1032    WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi);
1033
1034    return(client->noClientException);
1035}
1036
1037static PixmapPtr
1038fbShmCreatePixmap (pScreen, width, height, depth, addr)
1039    ScreenPtr	pScreen;
1040    int		width;
1041    int		height;
1042    int		depth;
1043    char	*addr;
1044{
1045    register PixmapPtr pPixmap;
1046
1047    pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth);
1048    if (!pPixmap)
1049	return NullPixmap;
1050
1051    if (!(*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth,
1052	    BitsPerPixel(depth), PixmapBytePad(width, depth), (pointer)addr)) {
1053	(*pScreen->DestroyPixmap)(pPixmap);
1054	return NullPixmap;
1055    }
1056    return pPixmap;
1057}
1058
1059static int
1060ProcShmCreatePixmap(client)
1061    register ClientPtr client;
1062{
1063    PixmapPtr pMap;
1064    DrawablePtr pDraw;
1065    DepthPtr pDepth;
1066    register int i, rc;
1067    ShmDescPtr shmdesc;
1068    REQUEST(xShmCreatePixmapReq);
1069    unsigned int width, height, depth;
1070    unsigned long size;
1071
1072    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1073    client->errorValue = stuff->pid;
1074    if (!sharedPixmaps)
1075	return BadImplementation;
1076    LEGAL_NEW_RESOURCE(stuff->pid, client);
1077    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
1078			   DixUnknownAccess);
1079    if (rc != Success)
1080	return rc;
1081
1082    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
1083
1084    width = stuff->width;
1085    height = stuff->height;
1086    depth = stuff->depth;
1087    if (!width || !height || !depth)
1088    {
1089	client->errorValue = 0;
1090        return BadValue;
1091    }
1092    if (width > 32767 || height > 32767)
1093	return BadAlloc;
1094
1095    if (stuff->depth != 1)
1096    {
1097        pDepth = pDraw->pScreen->allowedDepths;
1098        for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++)
1099	   if (pDepth->depth == stuff->depth)
1100               goto CreatePmap;
1101	client->errorValue = stuff->depth;
1102        return BadValue;
1103    }
1104
1105CreatePmap:
1106    size = PixmapBytePad(width, depth) * height;
1107    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
1108	if (size < width * height)
1109	    return BadAlloc;
1110    }
1111    /* thankfully, offset is unsigned */
1112    if (stuff->offset + size < size)
1113	return BadAlloc;
1114
1115    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
1116    pMap = (*shmFuncs[pDraw->pScreen->myNum]->CreatePixmap)(
1117			    pDraw->pScreen, stuff->width,
1118			    stuff->height, stuff->depth,
1119			    shmdesc->addr + stuff->offset);
1120    if (pMap)
1121    {
1122	pMap->devPrivates[shmPixmapPrivate].ptr = (pointer) shmdesc;
1123	shmdesc->refcnt++;
1124	pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1125	pMap->drawable.id = stuff->pid;
1126	if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap))
1127	{
1128	    return(client->noClientException);
1129	}
1130    }
1131    return (BadAlloc);
1132}
1133
1134static int
1135ProcShmDispatch (client)
1136    register ClientPtr	client;
1137{
1138    REQUEST(xReq);
1139    switch (stuff->data)
1140    {
1141    case X_ShmQueryVersion:
1142	return ProcShmQueryVersion(client);
1143    case X_ShmAttach:
1144	return ProcShmAttach(client);
1145    case X_ShmDetach:
1146	return ProcShmDetach(client);
1147    case X_ShmPutImage:
1148#ifdef PANORAMIX
1149        if ( !noPanoramiXExtension )
1150	   return ProcPanoramiXShmPutImage(client);
1151#endif
1152	return ProcShmPutImage(client);
1153    case X_ShmGetImage:
1154#ifdef PANORAMIX
1155        if ( !noPanoramiXExtension )
1156	   return ProcPanoramiXShmGetImage(client);
1157#endif
1158	return ProcShmGetImage(client);
1159    case X_ShmCreatePixmap:
1160#ifdef PANORAMIX
1161        if ( !noPanoramiXExtension )
1162	   return ProcPanoramiXShmCreatePixmap(client);
1163#endif
1164	   return ProcShmCreatePixmap(client);
1165    default:
1166	return BadRequest;
1167    }
1168}
1169
1170static void
1171SShmCompletionEvent(from, to)
1172    xShmCompletionEvent *from, *to;
1173{
1174    to->type = from->type;
1175    cpswaps(from->sequenceNumber, to->sequenceNumber);
1176    cpswapl(from->drawable, to->drawable);
1177    cpswaps(from->minorEvent, to->minorEvent);
1178    to->majorEvent = from->majorEvent;
1179    cpswapl(from->shmseg, to->shmseg);
1180    cpswapl(from->offset, to->offset);
1181}
1182
1183static int
1184SProcShmQueryVersion(client)
1185    register ClientPtr	client;
1186{
1187    register int n;
1188    REQUEST(xShmQueryVersionReq);
1189
1190    swaps(&stuff->length, n);
1191    return ProcShmQueryVersion(client);
1192}
1193
1194static int
1195SProcShmAttach(client)
1196    ClientPtr client;
1197{
1198    register int n;
1199    REQUEST(xShmAttachReq);
1200    swaps(&stuff->length, n);
1201    REQUEST_SIZE_MATCH(xShmAttachReq);
1202    swapl(&stuff->shmseg, n);
1203    swapl(&stuff->shmid, n);
1204    return ProcShmAttach(client);
1205}
1206
1207static int
1208SProcShmDetach(client)
1209    ClientPtr client;
1210{
1211    register int n;
1212    REQUEST(xShmDetachReq);
1213    swaps(&stuff->length, n);
1214    REQUEST_SIZE_MATCH(xShmDetachReq);
1215    swapl(&stuff->shmseg, n);
1216    return ProcShmDetach(client);
1217}
1218
1219static int
1220SProcShmPutImage(client)
1221    ClientPtr client;
1222{
1223    register int n;
1224    REQUEST(xShmPutImageReq);
1225    swaps(&stuff->length, n);
1226    REQUEST_SIZE_MATCH(xShmPutImageReq);
1227    swapl(&stuff->drawable, n);
1228    swapl(&stuff->gc, n);
1229    swaps(&stuff->totalWidth, n);
1230    swaps(&stuff->totalHeight, n);
1231    swaps(&stuff->srcX, n);
1232    swaps(&stuff->srcY, n);
1233    swaps(&stuff->srcWidth, n);
1234    swaps(&stuff->srcHeight, n);
1235    swaps(&stuff->dstX, n);
1236    swaps(&stuff->dstY, n);
1237    swapl(&stuff->shmseg, n);
1238    swapl(&stuff->offset, n);
1239    return ProcShmPutImage(client);
1240}
1241
1242static int
1243SProcShmGetImage(client)
1244    ClientPtr client;
1245{
1246    register int n;
1247    REQUEST(xShmGetImageReq);
1248    swaps(&stuff->length, n);
1249    REQUEST_SIZE_MATCH(xShmGetImageReq);
1250    swapl(&stuff->drawable, n);
1251    swaps(&stuff->x, n);
1252    swaps(&stuff->y, n);
1253    swaps(&stuff->width, n);
1254    swaps(&stuff->height, n);
1255    swapl(&stuff->planeMask, n);
1256    swapl(&stuff->shmseg, n);
1257    swapl(&stuff->offset, n);
1258    return ProcShmGetImage(client);
1259}
1260
1261static int
1262SProcShmCreatePixmap(client)
1263    ClientPtr client;
1264{
1265    register int n;
1266    REQUEST(xShmCreatePixmapReq);
1267    swaps(&stuff->length, n);
1268    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1269    swapl(&stuff->pid, n);
1270    swapl(&stuff->drawable, n);
1271    swaps(&stuff->width, n);
1272    swaps(&stuff->height, n);
1273    swapl(&stuff->shmseg, n);
1274    swapl(&stuff->offset, n);
1275    return ProcShmCreatePixmap(client);
1276}
1277
1278static int
1279SProcShmDispatch (client)
1280    register ClientPtr	client;
1281{
1282    REQUEST(xReq);
1283    switch (stuff->data)
1284    {
1285    case X_ShmQueryVersion:
1286	return SProcShmQueryVersion(client);
1287    case X_ShmAttach:
1288	return SProcShmAttach(client);
1289    case X_ShmDetach:
1290	return SProcShmDetach(client);
1291    case X_ShmPutImage:
1292	return SProcShmPutImage(client);
1293    case X_ShmGetImage:
1294	return SProcShmGetImage(client);
1295    case X_ShmCreatePixmap:
1296	return SProcShmCreatePixmap(client);
1297    default:
1298	return BadRequest;
1299    }
1300}
1301