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