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