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