shm.c revision 4642e01f
105b261ecSmrg/************************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1989, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrg********************************************************/
2605b261ecSmrg
2705b261ecSmrg/* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */
2805b261ecSmrg
2905b261ecSmrg
3005b261ecSmrg#define SHM
3105b261ecSmrg
3205b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3305b261ecSmrg#include <dix-config.h>
3405b261ecSmrg#endif
3505b261ecSmrg
3605b261ecSmrg#include <sys/types.h>
3705b261ecSmrg#include <sys/ipc.h>
3805b261ecSmrg#include <sys/shm.h>
3905b261ecSmrg#include <unistd.h>
4005b261ecSmrg#include <sys/stat.h>
4105b261ecSmrg#define NEED_REPLIES
4205b261ecSmrg#define NEED_EVENTS
4305b261ecSmrg#include <X11/X.h>
4405b261ecSmrg#include <X11/Xproto.h>
4505b261ecSmrg#include "misc.h"
4605b261ecSmrg#include "os.h"
4705b261ecSmrg#include "dixstruct.h"
4805b261ecSmrg#include "resource.h"
4905b261ecSmrg#include "scrnintstr.h"
5005b261ecSmrg#include "windowstr.h"
5105b261ecSmrg#include "pixmapstr.h"
5205b261ecSmrg#include "gcstruct.h"
5305b261ecSmrg#include "extnsionst.h"
5405b261ecSmrg#include "servermd.h"
554642e01fSmrg#include "shmint.h"
564642e01fSmrg#include "xace.h"
5705b261ecSmrg#define _XSHM_SERVER_
5805b261ecSmrg#include <X11/extensions/shmstr.h>
5905b261ecSmrg#include <X11/Xfuncproto.h>
6005b261ecSmrg
614642e01fSmrg/* Needed for Solaris cross-zone shared memory extension */
624642e01fSmrg#ifdef HAVE_SHMCTL64
634642e01fSmrg#include <sys/ipc_impl.h>
644642e01fSmrg#define SHMSTAT(id, buf)	shmctl64(id, IPC_STAT64, buf)
654642e01fSmrg#define SHMSTAT_TYPE 		struct shmid_ds64
664642e01fSmrg#define SHMPERM_TYPE 		struct ipc_perm64
674642e01fSmrg#define SHM_PERM(buf) 		buf.shmx_perm
684642e01fSmrg#define SHM_SEGSZ(buf)		buf.shmx_segsz
694642e01fSmrg#define SHMPERM_UID(p)		p->ipcx_uid
704642e01fSmrg#define SHMPERM_CUID(p)		p->ipcx_cuid
714642e01fSmrg#define SHMPERM_GID(p)		p->ipcx_gid
724642e01fSmrg#define SHMPERM_CGID(p)		p->ipcx_cgid
734642e01fSmrg#define SHMPERM_MODE(p)		p->ipcx_mode
744642e01fSmrg#define SHMPERM_ZONEID(p)	p->ipcx_zoneid
754642e01fSmrg#else
764642e01fSmrg#define SHMSTAT(id, buf) 	shmctl(id, IPC_STAT, buf)
774642e01fSmrg#define SHMSTAT_TYPE 		struct shmid_ds
784642e01fSmrg#define SHMPERM_TYPE 		struct ipc_perm
794642e01fSmrg#define SHM_PERM(buf) 		buf.shm_perm
804642e01fSmrg#define SHM_SEGSZ(buf)		buf.shm_segsz
814642e01fSmrg#define SHMPERM_UID(p)		p->uid
824642e01fSmrg#define SHMPERM_CUID(p)		p->cuid
834642e01fSmrg#define SHMPERM_GID(p)		p->gid
844642e01fSmrg#define SHMPERM_CGID(p)		p->cgid
854642e01fSmrg#define SHMPERM_MODE(p)		p->mode
864642e01fSmrg#endif
874642e01fSmrg
8805b261ecSmrg#ifdef PANORAMIX
8905b261ecSmrg#include "panoramiX.h"
9005b261ecSmrg#include "panoramiXsrv.h"
9105b261ecSmrg#endif
9205b261ecSmrg
9305b261ecSmrg#include "modinit.h"
9405b261ecSmrg
9505b261ecSmrgtypedef struct _ShmDesc {
9605b261ecSmrg    struct _ShmDesc *next;
9705b261ecSmrg    int shmid;
9805b261ecSmrg    int refcnt;
9905b261ecSmrg    char *addr;
10005b261ecSmrg    Bool writable;
10105b261ecSmrg    unsigned long size;
10205b261ecSmrg} ShmDescRec, *ShmDescPtr;
10305b261ecSmrg
10405b261ecSmrgstatic PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS);
10505b261ecSmrgstatic int ShmDetachSegment(
10605b261ecSmrg    pointer		/* value */,
10705b261ecSmrg    XID			/* shmseg */
10805b261ecSmrg    );
10905b261ecSmrgstatic void ShmResetProc(
11005b261ecSmrg    ExtensionEntry *	/* extEntry */
11105b261ecSmrg    );
11205b261ecSmrgstatic void SShmCompletionEvent(
11305b261ecSmrg    xShmCompletionEvent * /* from */,
11405b261ecSmrg    xShmCompletionEvent * /* to */
11505b261ecSmrg    );
11605b261ecSmrg
11705b261ecSmrgstatic Bool ShmDestroyPixmap (PixmapPtr pPixmap);
11805b261ecSmrg
11905b261ecSmrgstatic DISPATCH_PROC(ProcShmAttach);
12005b261ecSmrgstatic DISPATCH_PROC(ProcShmCreatePixmap);
12105b261ecSmrgstatic DISPATCH_PROC(ProcShmDetach);
12205b261ecSmrgstatic DISPATCH_PROC(ProcShmDispatch);
12305b261ecSmrgstatic DISPATCH_PROC(ProcShmGetImage);
12405b261ecSmrgstatic DISPATCH_PROC(ProcShmPutImage);
12505b261ecSmrgstatic DISPATCH_PROC(ProcShmQueryVersion);
12605b261ecSmrgstatic DISPATCH_PROC(SProcShmAttach);
12705b261ecSmrgstatic DISPATCH_PROC(SProcShmCreatePixmap);
12805b261ecSmrgstatic DISPATCH_PROC(SProcShmDetach);
12905b261ecSmrgstatic DISPATCH_PROC(SProcShmDispatch);
13005b261ecSmrgstatic DISPATCH_PROC(SProcShmGetImage);
13105b261ecSmrgstatic DISPATCH_PROC(SProcShmPutImage);
13205b261ecSmrgstatic DISPATCH_PROC(SProcShmQueryVersion);
13305b261ecSmrg
13405b261ecSmrgstatic unsigned char ShmReqCode;
13505b261ecSmrg_X_EXPORT int ShmCompletionCode;
13605b261ecSmrg_X_EXPORT int BadShmSegCode;
13705b261ecSmrg_X_EXPORT RESTYPE ShmSegType;
13805b261ecSmrgstatic ShmDescPtr Shmsegs;
13905b261ecSmrgstatic Bool sharedPixmaps;
14005b261ecSmrgstatic ShmFuncsPtr shmFuncs[MAXSCREENS];
14105b261ecSmrgstatic DestroyPixmapProcPtr destroyPixmap[MAXSCREENS];
1424642e01fSmrgstatic int shmPixmapPrivateIndex;
1434642e01fSmrgstatic DevPrivateKey shmPixmapPrivate = &shmPixmapPrivateIndex;
1444642e01fSmrgstatic ShmFuncs miFuncs = {NULL, NULL};
1454642e01fSmrgstatic ShmFuncs fbFuncs = {fbShmCreatePixmap, NULL};
14605b261ecSmrg
14705b261ecSmrg#define VERIFY_SHMSEG(shmseg,shmdesc,client) \
14805b261ecSmrg{ \
14905b261ecSmrg    shmdesc = (ShmDescPtr)LookupIDByType(shmseg, ShmSegType); \
15005b261ecSmrg    if (!shmdesc) \
15105b261ecSmrg    { \
15205b261ecSmrg	client->errorValue = shmseg; \
15305b261ecSmrg	return BadShmSegCode; \
15405b261ecSmrg    } \
15505b261ecSmrg}
15605b261ecSmrg
15705b261ecSmrg#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \
15805b261ecSmrg{ \
15905b261ecSmrg    VERIFY_SHMSEG(shmseg, shmdesc, client); \
16005b261ecSmrg    if ((offset & 3) || (offset > shmdesc->size)) \
16105b261ecSmrg    { \
16205b261ecSmrg	client->errorValue = offset; \
16305b261ecSmrg	return BadValue; \
16405b261ecSmrg    } \
16505b261ecSmrg    if (needwrite && !shmdesc->writable) \
16605b261ecSmrg	return BadAccess; \
16705b261ecSmrg}
16805b261ecSmrg
16905b261ecSmrg#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \
17005b261ecSmrg{ \
17105b261ecSmrg    if ((offset + len) > shmdesc->size) \
17205b261ecSmrg    { \
17305b261ecSmrg	return BadAccess; \
17405b261ecSmrg    } \
17505b261ecSmrg}
17605b261ecSmrg
17705b261ecSmrg
17805b261ecSmrg#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
17905b261ecSmrg#include <sys/signal.h>
18005b261ecSmrg
18105b261ecSmrgstatic Bool badSysCall = FALSE;
18205b261ecSmrg
18305b261ecSmrgstatic void
1844642e01fSmrgSigSysHandler(int signo)
18505b261ecSmrg{
18605b261ecSmrg    badSysCall = TRUE;
18705b261ecSmrg}
18805b261ecSmrg
1894642e01fSmrgstatic Bool CheckForShmSyscall(void)
19005b261ecSmrg{
19105b261ecSmrg    void (*oldHandler)();
19205b261ecSmrg    int shmid = -1;
19305b261ecSmrg
19405b261ecSmrg    /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
19505b261ecSmrg    oldHandler = signal(SIGSYS, SigSysHandler);
19605b261ecSmrg
19705b261ecSmrg    badSysCall = FALSE;
19805b261ecSmrg    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
19905b261ecSmrg
20005b261ecSmrg    if (shmid != -1)
20105b261ecSmrg    {
20205b261ecSmrg        /* Successful allocation - clean up */
20305b261ecSmrg	shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL);
20405b261ecSmrg    }
20505b261ecSmrg    else
20605b261ecSmrg    {
20705b261ecSmrg        /* Allocation failed */
20805b261ecSmrg        badSysCall = TRUE;
20905b261ecSmrg    }
21005b261ecSmrg    signal(SIGSYS, oldHandler);
21105b261ecSmrg    return(!badSysCall);
21205b261ecSmrg}
21305b261ecSmrg
21405b261ecSmrg#define MUST_CHECK_FOR_SHM_SYSCALL
21505b261ecSmrg
21605b261ecSmrg#endif
21705b261ecSmrg
21805b261ecSmrgvoid
21905b261ecSmrgShmExtensionInit(INITARGS)
22005b261ecSmrg{
22105b261ecSmrg    ExtensionEntry *extEntry;
22205b261ecSmrg    int i;
22305b261ecSmrg
22405b261ecSmrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL
22505b261ecSmrg    if (!CheckForShmSyscall())
22605b261ecSmrg    {
22705b261ecSmrg	ErrorF("MIT-SHM extension disabled due to lack of kernel support\n");
22805b261ecSmrg	return;
22905b261ecSmrg    }
23005b261ecSmrg#endif
23105b261ecSmrg
23205b261ecSmrg    sharedPixmaps = xFalse;
23305b261ecSmrg    {
23405b261ecSmrg      sharedPixmaps = xTrue;
23505b261ecSmrg      for (i = 0; i < screenInfo.numScreens; i++)
23605b261ecSmrg      {
23705b261ecSmrg	if (!shmFuncs[i])
23805b261ecSmrg	    shmFuncs[i] = &miFuncs;
23905b261ecSmrg	if (!shmFuncs[i]->CreatePixmap)
24005b261ecSmrg	    sharedPixmaps = xFalse;
24105b261ecSmrg      }
24205b261ecSmrg      if (sharedPixmaps)
24305b261ecSmrg	for (i = 0; i < screenInfo.numScreens; i++)
24405b261ecSmrg	{
24505b261ecSmrg	    destroyPixmap[i] = screenInfo.screens[i]->DestroyPixmap;
24605b261ecSmrg	    screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap;
24705b261ecSmrg	}
24805b261ecSmrg    }
24905b261ecSmrg    ShmSegType = CreateNewResourceType(ShmDetachSegment);
25005b261ecSmrg    if (ShmSegType &&
25105b261ecSmrg	(extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors,
25205b261ecSmrg				 ProcShmDispatch, SProcShmDispatch,
25305b261ecSmrg				 ShmResetProc, StandardMinorOpcode)))
25405b261ecSmrg    {
25505b261ecSmrg	ShmReqCode = (unsigned char)extEntry->base;
25605b261ecSmrg	ShmCompletionCode = extEntry->eventBase;
25705b261ecSmrg	BadShmSegCode = extEntry->errorBase;
25805b261ecSmrg	EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent;
25905b261ecSmrg    }
26005b261ecSmrg}
26105b261ecSmrg
26205b261ecSmrg/*ARGSUSED*/
26305b261ecSmrgstatic void
2644642e01fSmrgShmResetProc(ExtensionEntry *extEntry)
26505b261ecSmrg{
26605b261ecSmrg    int i;
26705b261ecSmrg
26805b261ecSmrg    for (i = 0; i < MAXSCREENS; i++)
26905b261ecSmrg    {
27005b261ecSmrg	shmFuncs[i] = (ShmFuncsPtr)NULL;
27105b261ecSmrg    }
27205b261ecSmrg}
27305b261ecSmrg
2744642e01fSmrg_X_EXPORT void
2754642e01fSmrgShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs)
27605b261ecSmrg{
27705b261ecSmrg    shmFuncs[pScreen->myNum] = funcs;
27805b261ecSmrg}
27905b261ecSmrg
28005b261ecSmrgstatic Bool
28105b261ecSmrgShmDestroyPixmap (PixmapPtr pPixmap)
28205b261ecSmrg{
28305b261ecSmrg    ScreenPtr	    pScreen = pPixmap->drawable.pScreen;
28405b261ecSmrg    Bool	    ret;
28505b261ecSmrg    if (pPixmap->refcnt == 1)
28605b261ecSmrg    {
28705b261ecSmrg	ShmDescPtr  shmdesc;
2884642e01fSmrg	shmdesc = (ShmDescPtr)dixLookupPrivate(&pPixmap->devPrivates,
2894642e01fSmrg					       shmPixmapPrivate);
29005b261ecSmrg	if (shmdesc)
29105b261ecSmrg	    ShmDetachSegment ((pointer) shmdesc, pPixmap->drawable.id);
29205b261ecSmrg    }
29305b261ecSmrg
29405b261ecSmrg    pScreen->DestroyPixmap = destroyPixmap[pScreen->myNum];
29505b261ecSmrg    ret = (*pScreen->DestroyPixmap) (pPixmap);
29605b261ecSmrg    destroyPixmap[pScreen->myNum] = pScreen->DestroyPixmap;
29705b261ecSmrg    pScreen->DestroyPixmap = ShmDestroyPixmap;
29805b261ecSmrg    return ret;
29905b261ecSmrg}
30005b261ecSmrg
3014642e01fSmrg_X_EXPORT void
3024642e01fSmrgShmRegisterFbFuncs(ScreenPtr pScreen)
30305b261ecSmrg{
30405b261ecSmrg    shmFuncs[pScreen->myNum] = &fbFuncs;
30505b261ecSmrg}
30605b261ecSmrg
30705b261ecSmrgstatic int
3084642e01fSmrgProcShmQueryVersion(ClientPtr client)
30905b261ecSmrg{
31005b261ecSmrg    xShmQueryVersionReply rep;
3114642e01fSmrg    int n;
31205b261ecSmrg
31305b261ecSmrg    REQUEST_SIZE_MATCH(xShmQueryVersionReq);
31405b261ecSmrg    rep.type = X_Reply;
31505b261ecSmrg    rep.length = 0;
31605b261ecSmrg    rep.sequenceNumber = client->sequence;
31705b261ecSmrg    rep.sharedPixmaps = sharedPixmaps;
3184642e01fSmrg    rep.pixmapFormat = sharedPixmaps ? ZPixmap : 0;
31905b261ecSmrg    rep.majorVersion = SHM_MAJOR_VERSION;
32005b261ecSmrg    rep.minorVersion = SHM_MINOR_VERSION;
32105b261ecSmrg    rep.uid = geteuid();
32205b261ecSmrg    rep.gid = getegid();
32305b261ecSmrg    if (client->swapped) {
32405b261ecSmrg    	swaps(&rep.sequenceNumber, n);
32505b261ecSmrg    	swapl(&rep.length, n);
32605b261ecSmrg	swaps(&rep.majorVersion, n);
32705b261ecSmrg	swaps(&rep.minorVersion, n);
32805b261ecSmrg	swaps(&rep.uid, n);
32905b261ecSmrg	swaps(&rep.gid, n);
33005b261ecSmrg    }
33105b261ecSmrg    WriteToClient(client, sizeof(xShmQueryVersionReply), (char *)&rep);
33205b261ecSmrg    return (client->noClientException);
33305b261ecSmrg}
33405b261ecSmrg
33505b261ecSmrg/*
33605b261ecSmrg * Simulate the access() system call for a shared memory segement,
33705b261ecSmrg * using the credentials from the client if available
33805b261ecSmrg */
33905b261ecSmrgstatic int
3404642e01fSmrgshm_access(ClientPtr client, SHMPERM_TYPE *perm, int readonly)
34105b261ecSmrg{
34205b261ecSmrg    int uid, gid;
34305b261ecSmrg    mode_t mask;
3444642e01fSmrg    int uidset = 0, gidset = 0;
3454642e01fSmrg    LocalClientCredRec *lcc;
3464642e01fSmrg
3474642e01fSmrg    if (GetLocalClientCreds(client, &lcc) != -1) {
34805b261ecSmrg
3494642e01fSmrg	if (lcc->fieldsSet & LCC_UID_SET) {
3504642e01fSmrg	    uid = lcc->euid;
3514642e01fSmrg	    uidset = 1;
3524642e01fSmrg	}
3534642e01fSmrg	if (lcc->fieldsSet & LCC_GID_SET) {
3544642e01fSmrg	    gid = lcc->egid;
3554642e01fSmrg	    gidset = 1;
3564642e01fSmrg	}
3574642e01fSmrg
3584642e01fSmrg#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID)
3594642e01fSmrg	if ( ((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1)
3604642e01fSmrg	     || (lcc->zoneid != SHMPERM_ZONEID(perm))) {
3614642e01fSmrg		uidset = 0;
3624642e01fSmrg		gidset = 0;
36305b261ecSmrg	}
3644642e01fSmrg#endif
3654642e01fSmrg	FreeLocalClientCreds(lcc);
3664642e01fSmrg
3674642e01fSmrg	if (uidset) {
3684642e01fSmrg	    /* User id 0 always gets access */
3694642e01fSmrg	    if (uid == 0) {
3704642e01fSmrg		return 0;
3714642e01fSmrg	    }
3724642e01fSmrg	    /* Check the owner */
3734642e01fSmrg	    if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) {
3744642e01fSmrg		mask = S_IRUSR;
3754642e01fSmrg		if (!readonly) {
3764642e01fSmrg		    mask |= S_IWUSR;
3774642e01fSmrg		}
3784642e01fSmrg		return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
37905b261ecSmrg	    }
38005b261ecSmrg	}
3814642e01fSmrg
3824642e01fSmrg	if (gidset) {
3834642e01fSmrg	    /* Check the group */
3844642e01fSmrg	    if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) {
3854642e01fSmrg		mask = S_IRGRP;
3864642e01fSmrg		if (!readonly) {
3874642e01fSmrg		    mask |= S_IWGRP;
3884642e01fSmrg		}
3894642e01fSmrg		return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
39005b261ecSmrg	    }
39105b261ecSmrg	}
39205b261ecSmrg    }
39305b261ecSmrg    /* Otherwise, check everyone else */
39405b261ecSmrg    mask = S_IROTH;
39505b261ecSmrg    if (!readonly) {
39605b261ecSmrg	mask |= S_IWOTH;
39705b261ecSmrg    }
3984642e01fSmrg    return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
39905b261ecSmrg}
40005b261ecSmrg
40105b261ecSmrgstatic int
4024642e01fSmrgProcShmAttach(ClientPtr client)
40305b261ecSmrg{
4044642e01fSmrg    SHMSTAT_TYPE buf;
40505b261ecSmrg    ShmDescPtr shmdesc;
40605b261ecSmrg    REQUEST(xShmAttachReq);
40705b261ecSmrg
40805b261ecSmrg    REQUEST_SIZE_MATCH(xShmAttachReq);
40905b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
41005b261ecSmrg    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse))
41105b261ecSmrg    {
41205b261ecSmrg	client->errorValue = stuff->readOnly;
41305b261ecSmrg        return(BadValue);
41405b261ecSmrg    }
41505b261ecSmrg    for (shmdesc = Shmsegs;
41605b261ecSmrg	 shmdesc && (shmdesc->shmid != stuff->shmid);
41705b261ecSmrg	 shmdesc = shmdesc->next)
41805b261ecSmrg	;
41905b261ecSmrg    if (shmdesc)
42005b261ecSmrg    {
42105b261ecSmrg	if (!stuff->readOnly && !shmdesc->writable)
42205b261ecSmrg	    return BadAccess;
42305b261ecSmrg	shmdesc->refcnt++;
42405b261ecSmrg    }
42505b261ecSmrg    else
42605b261ecSmrg    {
42705b261ecSmrg	shmdesc = (ShmDescPtr) xalloc(sizeof(ShmDescRec));
42805b261ecSmrg	if (!shmdesc)
42905b261ecSmrg	    return BadAlloc;
43005b261ecSmrg	shmdesc->addr = shmat(stuff->shmid, 0,
43105b261ecSmrg			      stuff->readOnly ? SHM_RDONLY : 0);
43205b261ecSmrg	if ((shmdesc->addr == ((char *)-1)) ||
4334642e01fSmrg	    SHMSTAT(stuff->shmid, &buf))
43405b261ecSmrg	{
43505b261ecSmrg	    xfree(shmdesc);
43605b261ecSmrg	    return BadAccess;
43705b261ecSmrg	}
43805b261ecSmrg
43905b261ecSmrg	/* The attach was performed with root privs. We must
44005b261ecSmrg	 * do manual checking of access rights for the credentials
44105b261ecSmrg	 * of the client */
44205b261ecSmrg
4434642e01fSmrg	if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) {
44405b261ecSmrg	    shmdt(shmdesc->addr);
44505b261ecSmrg	    xfree(shmdesc);
44605b261ecSmrg	    return BadAccess;
44705b261ecSmrg	}
44805b261ecSmrg
44905b261ecSmrg	shmdesc->shmid = stuff->shmid;
45005b261ecSmrg	shmdesc->refcnt = 1;
45105b261ecSmrg	shmdesc->writable = !stuff->readOnly;
4524642e01fSmrg	shmdesc->size = SHM_SEGSZ(buf);
45305b261ecSmrg	shmdesc->next = Shmsegs;
45405b261ecSmrg	Shmsegs = shmdesc;
45505b261ecSmrg    }
45605b261ecSmrg    if (!AddResource(stuff->shmseg, ShmSegType, (pointer)shmdesc))
45705b261ecSmrg	return BadAlloc;
45805b261ecSmrg    return(client->noClientException);
45905b261ecSmrg}
46005b261ecSmrg
46105b261ecSmrg/*ARGSUSED*/
46205b261ecSmrgstatic int
4634642e01fSmrgShmDetachSegment(pointer value, /* must conform to DeleteType */
4644642e01fSmrg		 XID shmseg)
46505b261ecSmrg{
46605b261ecSmrg    ShmDescPtr shmdesc = (ShmDescPtr)value;
46705b261ecSmrg    ShmDescPtr *prev;
46805b261ecSmrg
46905b261ecSmrg    if (--shmdesc->refcnt)
47005b261ecSmrg	return TRUE;
47105b261ecSmrg    shmdt(shmdesc->addr);
47205b261ecSmrg    for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next)
47305b261ecSmrg	;
47405b261ecSmrg    *prev = shmdesc->next;
47505b261ecSmrg    xfree(shmdesc);
47605b261ecSmrg    return Success;
47705b261ecSmrg}
47805b261ecSmrg
47905b261ecSmrgstatic int
4804642e01fSmrgProcShmDetach(ClientPtr client)
48105b261ecSmrg{
48205b261ecSmrg    ShmDescPtr shmdesc;
48305b261ecSmrg    REQUEST(xShmDetachReq);
48405b261ecSmrg
48505b261ecSmrg    REQUEST_SIZE_MATCH(xShmDetachReq);
48605b261ecSmrg    VERIFY_SHMSEG(stuff->shmseg, shmdesc, client);
48705b261ecSmrg    FreeResource(stuff->shmseg, RT_NONE);
48805b261ecSmrg    return(client->noClientException);
48905b261ecSmrg}
49005b261ecSmrg
4914642e01fSmrg/*
4924642e01fSmrg * If the given request doesn't exactly match PutImage's constraints,
4934642e01fSmrg * wrap the image in a scratch pixmap header and let CopyArea sort it out.
4944642e01fSmrg */
49505b261ecSmrgstatic void
4964642e01fSmrgdoShmPutImage(DrawablePtr dst, GCPtr pGC,
4974642e01fSmrg	      int depth, unsigned int format,
4984642e01fSmrg	      int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
4994642e01fSmrg	      char *data)
50005b261ecSmrg{
5014642e01fSmrg    PixmapPtr pPixmap;
5024642e01fSmrg
5034642e01fSmrg    pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth,
5044642e01fSmrg				     BitsPerPixel(depth),
5054642e01fSmrg				     PixmapBytePad(w, depth),
5064642e01fSmrg				     data);
5074642e01fSmrg    if (!pPixmap)
50805b261ecSmrg	return;
5094642e01fSmrg    pGC->ops->CopyArea((DrawablePtr)pPixmap, dst, pGC, sx, sy, sw, sh, dx, dy);
5104642e01fSmrg    FreeScratchPixmapHeader(pPixmap);
51105b261ecSmrg}
51205b261ecSmrg
51305b261ecSmrg#ifdef PANORAMIX
51405b261ecSmrgstatic int
5154642e01fSmrgProcPanoramiXShmPutImage(ClientPtr client)
51605b261ecSmrg{
51705b261ecSmrg    int			 j, result = 0, orig_x, orig_y;
51805b261ecSmrg    PanoramiXRes	*draw, *gc;
51905b261ecSmrg    Bool		 sendEvent, isRoot;
52005b261ecSmrg
52105b261ecSmrg    REQUEST(xShmPutImageReq);
52205b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
52305b261ecSmrg
52405b261ecSmrg    if(!(draw = (PanoramiXRes *)SecurityLookupIDByClass(
52505b261ecSmrg                client, stuff->drawable, XRC_DRAWABLE, DixWriteAccess)))
52605b261ecSmrg        return BadDrawable;
52705b261ecSmrg
52805b261ecSmrg    if(!(gc = (PanoramiXRes *)SecurityLookupIDByType(
52905b261ecSmrg                client, stuff->gc, XRT_GC, DixReadAccess)))
53005b261ecSmrg        return BadGC;
53105b261ecSmrg
53205b261ecSmrg    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
53305b261ecSmrg
53405b261ecSmrg    orig_x = stuff->dstX;
53505b261ecSmrg    orig_y = stuff->dstY;
53605b261ecSmrg    sendEvent = stuff->sendEvent;
53705b261ecSmrg    stuff->sendEvent = 0;
53805b261ecSmrg    FOR_NSCREENS(j) {
53905b261ecSmrg	if(!j) stuff->sendEvent = sendEvent;
54005b261ecSmrg	stuff->drawable = draw->info[j].id;
54105b261ecSmrg	stuff->gc = gc->info[j].id;
54205b261ecSmrg	if (isRoot) {
54305b261ecSmrg	    stuff->dstX = orig_x - panoramiXdataPtr[j].x;
54405b261ecSmrg	    stuff->dstY = orig_y - panoramiXdataPtr[j].y;
54505b261ecSmrg	}
54605b261ecSmrg	result = ProcShmPutImage(client);
54705b261ecSmrg	if(result != client->noClientException) break;
54805b261ecSmrg    }
54905b261ecSmrg    return(result);
55005b261ecSmrg}
55105b261ecSmrg
55205b261ecSmrgstatic int
55305b261ecSmrgProcPanoramiXShmGetImage(ClientPtr client)
55405b261ecSmrg{
55505b261ecSmrg    PanoramiXRes	*draw;
55605b261ecSmrg    DrawablePtr 	drawables[MAXSCREENS];
55705b261ecSmrg    DrawablePtr 	pDraw;
55805b261ecSmrg    xShmGetImageReply	xgi;
55905b261ecSmrg    ShmDescPtr		shmdesc;
56005b261ecSmrg    int         	i, x, y, w, h, format, rc;
56105b261ecSmrg    Mask		plane = 0, planemask;
56205b261ecSmrg    long		lenPer = 0, length, widthBytesLine;
56305b261ecSmrg    Bool		isRoot;
56405b261ecSmrg
56505b261ecSmrg    REQUEST(xShmGetImageReq);
56605b261ecSmrg
56705b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
56805b261ecSmrg
56905b261ecSmrg    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
57005b261ecSmrg	client->errorValue = stuff->format;
57105b261ecSmrg        return(BadValue);
57205b261ecSmrg    }
57305b261ecSmrg
57405b261ecSmrg    if(!(draw = (PanoramiXRes *)SecurityLookupIDByClass(
57505b261ecSmrg		client, stuff->drawable, XRC_DRAWABLE, DixWriteAccess)))
57605b261ecSmrg	return BadDrawable;
57705b261ecSmrg
57805b261ecSmrg    if (draw->type == XRT_PIXMAP)
57905b261ecSmrg	return ProcShmGetImage(client);
58005b261ecSmrg
58105b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0,
5824642e01fSmrg			   DixReadAccess);
58305b261ecSmrg    if (rc != Success)
58405b261ecSmrg	return rc;
58505b261ecSmrg
58605b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
58705b261ecSmrg
58805b261ecSmrg    x = stuff->x;
58905b261ecSmrg    y = stuff->y;
59005b261ecSmrg    w = stuff->width;
59105b261ecSmrg    h = stuff->height;
59205b261ecSmrg    format = stuff->format;
59305b261ecSmrg    planemask = stuff->planeMask;
59405b261ecSmrg
59505b261ecSmrg    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
59605b261ecSmrg
59705b261ecSmrg    if(isRoot) {
59805b261ecSmrg      if( /* check for being onscreen */
59905b261ecSmrg	x < 0 || x + w > PanoramiXPixWidth ||
60005b261ecSmrg	y < 0 || y + h > PanoramiXPixHeight )
60105b261ecSmrg	    return(BadMatch);
60205b261ecSmrg    } else {
60305b261ecSmrg      if( /* check for being onscreen */
60405b261ecSmrg	panoramiXdataPtr[0].x + pDraw->x + x < 0 ||
60505b261ecSmrg	panoramiXdataPtr[0].x + pDraw->x + x + w > PanoramiXPixWidth ||
60605b261ecSmrg        panoramiXdataPtr[0].y + pDraw->y + y < 0 ||
60705b261ecSmrg	panoramiXdataPtr[0].y + pDraw->y + y + h > PanoramiXPixHeight ||
60805b261ecSmrg	 /* check for being inside of border */
60905b261ecSmrg       	x < - wBorderWidth((WindowPtr)pDraw) ||
61005b261ecSmrg	x + w > wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width ||
61105b261ecSmrg	y < -wBorderWidth((WindowPtr)pDraw) ||
61205b261ecSmrg	y + h > wBorderWidth ((WindowPtr)pDraw) + (int)pDraw->height)
61305b261ecSmrg	    return(BadMatch);
61405b261ecSmrg    }
61505b261ecSmrg
61605b261ecSmrg    drawables[0] = pDraw;
61705b261ecSmrg    for(i = 1; i < PanoramiXNumScreens; i++) {
61805b261ecSmrg	rc = dixLookupDrawable(drawables+i, draw->info[i].id, client, 0,
6194642e01fSmrg			       DixReadAccess);
62005b261ecSmrg	if (rc != Success)
62105b261ecSmrg	    return rc;
62205b261ecSmrg    }
62305b261ecSmrg
62405b261ecSmrg    xgi.visual = wVisual(((WindowPtr)pDraw));
62505b261ecSmrg    xgi.type = X_Reply;
62605b261ecSmrg    xgi.length = 0;
62705b261ecSmrg    xgi.sequenceNumber = client->sequence;
62805b261ecSmrg    xgi.depth = pDraw->depth;
62905b261ecSmrg
63005b261ecSmrg    if(format == ZPixmap) {
63105b261ecSmrg	widthBytesLine = PixmapBytePad(w, pDraw->depth);
63205b261ecSmrg	length = widthBytesLine * h;
63305b261ecSmrg    } else {
63405b261ecSmrg	widthBytesLine = PixmapBytePad(w, 1);
63505b261ecSmrg	lenPer = widthBytesLine * h;
63605b261ecSmrg	plane = ((Mask)1) << (pDraw->depth - 1);
63705b261ecSmrg	length = lenPer * Ones(planemask & (plane | (plane - 1)));
63805b261ecSmrg    }
63905b261ecSmrg
64005b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
64105b261ecSmrg    xgi.size = length;
64205b261ecSmrg
64305b261ecSmrg    if (length == 0) {/* nothing to do */ }
64405b261ecSmrg    else if (format == ZPixmap) {
64505b261ecSmrg	    XineramaGetImageData(drawables, x, y, w, h, format, planemask,
64605b261ecSmrg					shmdesc->addr + stuff->offset,
64705b261ecSmrg					widthBytesLine, isRoot);
64805b261ecSmrg    } else {
64905b261ecSmrg
65005b261ecSmrg	length = stuff->offset;
65105b261ecSmrg        for (; plane; plane >>= 1) {
65205b261ecSmrg	    if (planemask & plane) {
65305b261ecSmrg		XineramaGetImageData(drawables, x, y, w, h,
65405b261ecSmrg				     format, plane, shmdesc->addr + length,
65505b261ecSmrg				     widthBytesLine, isRoot);
65605b261ecSmrg		length += lenPer;
65705b261ecSmrg	    }
65805b261ecSmrg	}
65905b261ecSmrg    }
66005b261ecSmrg
66105b261ecSmrg    if (client->swapped) {
6624642e01fSmrg	int n;
66305b261ecSmrg    	swaps(&xgi.sequenceNumber, n);
66405b261ecSmrg    	swapl(&xgi.length, n);
66505b261ecSmrg	swapl(&xgi.visual, n);
66605b261ecSmrg	swapl(&xgi.size, n);
66705b261ecSmrg    }
66805b261ecSmrg    WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi);
66905b261ecSmrg
67005b261ecSmrg    return(client->noClientException);
67105b261ecSmrg}
67205b261ecSmrg
67305b261ecSmrgstatic int
6744642e01fSmrgProcPanoramiXShmCreatePixmap(ClientPtr client)
67505b261ecSmrg{
67605b261ecSmrg    ScreenPtr pScreen = NULL;
67705b261ecSmrg    PixmapPtr pMap = NULL;
67805b261ecSmrg    DrawablePtr pDraw;
67905b261ecSmrg    DepthPtr pDepth;
68005b261ecSmrg    int i, j, result, rc;
68105b261ecSmrg    ShmDescPtr shmdesc;
68205b261ecSmrg    REQUEST(xShmCreatePixmapReq);
68305b261ecSmrg    unsigned int width, height, depth;
68405b261ecSmrg    unsigned long size;
68505b261ecSmrg    PanoramiXRes *newPix;
68605b261ecSmrg
68705b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
68805b261ecSmrg    client->errorValue = stuff->pid;
68905b261ecSmrg    if (!sharedPixmaps)
69005b261ecSmrg	return BadImplementation;
69105b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->pid, client);
69205b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
6934642e01fSmrg			   DixGetAttrAccess);
69405b261ecSmrg    if (rc != Success)
69505b261ecSmrg	return rc;
69605b261ecSmrg
69705b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
69805b261ecSmrg
69905b261ecSmrg    width = stuff->width;
70005b261ecSmrg    height = stuff->height;
70105b261ecSmrg    depth = stuff->depth;
70205b261ecSmrg    if (!width || !height || !depth)
70305b261ecSmrg    {
70405b261ecSmrg	client->errorValue = 0;
70505b261ecSmrg        return BadValue;
70605b261ecSmrg    }
70705b261ecSmrg    if (width > 32767 || height > 32767)
70805b261ecSmrg        return BadAlloc;
70905b261ecSmrg
71005b261ecSmrg    if (stuff->depth != 1)
71105b261ecSmrg    {
71205b261ecSmrg        pDepth = pDraw->pScreen->allowedDepths;
71305b261ecSmrg        for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++)
71405b261ecSmrg	   if (pDepth->depth == stuff->depth)
71505b261ecSmrg               goto CreatePmap;
71605b261ecSmrg	client->errorValue = stuff->depth;
71705b261ecSmrg        return BadValue;
71805b261ecSmrg    }
71905b261ecSmrg
72005b261ecSmrgCreatePmap:
72105b261ecSmrg    size = PixmapBytePad(width, depth) * height;
72205b261ecSmrg    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
72305b261ecSmrg        if (size < width * height)
72405b261ecSmrg            return BadAlloc;
72505b261ecSmrg    }
72605b261ecSmrg    /* thankfully, offset is unsigned */
72705b261ecSmrg    if (stuff->offset + size < size)
72805b261ecSmrg	return BadAlloc;
72905b261ecSmrg
73005b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
73105b261ecSmrg
73205b261ecSmrg    if(!(newPix = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes))))
73305b261ecSmrg	return BadAlloc;
73405b261ecSmrg
73505b261ecSmrg    newPix->type = XRT_PIXMAP;
73605b261ecSmrg    newPix->u.pix.shared = TRUE;
73705b261ecSmrg    newPix->info[0].id = stuff->pid;
73805b261ecSmrg    for(j = 1; j < PanoramiXNumScreens; j++)
73905b261ecSmrg	newPix->info[j].id = FakeClientID(client->index);
74005b261ecSmrg
74105b261ecSmrg    result = (client->noClientException);
74205b261ecSmrg
74305b261ecSmrg    FOR_NSCREENS(j) {
74405b261ecSmrg	pScreen = screenInfo.screens[j];
74505b261ecSmrg
74605b261ecSmrg	pMap = (*shmFuncs[j]->CreatePixmap)(pScreen,
74705b261ecSmrg				stuff->width, stuff->height, stuff->depth,
74805b261ecSmrg				shmdesc->addr + stuff->offset);
74905b261ecSmrg
75005b261ecSmrg	if (pMap) {
7514642e01fSmrg	    dixSetPrivate(&pMap->devPrivates, shmPixmapPrivate, shmdesc);
75205b261ecSmrg            shmdesc->refcnt++;
75305b261ecSmrg	    pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
75405b261ecSmrg	    pMap->drawable.id = newPix->info[j].id;
75505b261ecSmrg	    if (!AddResource(newPix->info[j].id, RT_PIXMAP, (pointer)pMap)) {
75605b261ecSmrg		(*pScreen->DestroyPixmap)(pMap);
75705b261ecSmrg		result = BadAlloc;
75805b261ecSmrg		break;
75905b261ecSmrg	    }
76005b261ecSmrg	} else {
76105b261ecSmrg	   result = BadAlloc;
76205b261ecSmrg	   break;
76305b261ecSmrg	}
76405b261ecSmrg    }
76505b261ecSmrg
76605b261ecSmrg    if(result == BadAlloc) {
76705b261ecSmrg	while(j--) {
76805b261ecSmrg	    (*pScreen->DestroyPixmap)(pMap);
76905b261ecSmrg	    FreeResource(newPix->info[j].id, RT_NONE);
77005b261ecSmrg	}
77105b261ecSmrg	xfree(newPix);
77205b261ecSmrg    } else
77305b261ecSmrg	AddResource(stuff->pid, XRT_PIXMAP, newPix);
77405b261ecSmrg
77505b261ecSmrg    return result;
77605b261ecSmrg}
77705b261ecSmrg
77805b261ecSmrg#endif
77905b261ecSmrg
78005b261ecSmrgstatic int
7814642e01fSmrgProcShmPutImage(ClientPtr client)
78205b261ecSmrg{
78305b261ecSmrg    GCPtr pGC;
78405b261ecSmrg    DrawablePtr pDraw;
78505b261ecSmrg    long length;
78605b261ecSmrg    ShmDescPtr shmdesc;
78705b261ecSmrg    REQUEST(xShmPutImageReq);
78805b261ecSmrg
78905b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
7904642e01fSmrg    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
79105b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client);
79205b261ecSmrg    if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse))
79305b261ecSmrg	return BadValue;
79405b261ecSmrg    if (stuff->format == XYBitmap)
79505b261ecSmrg    {
79605b261ecSmrg        if (stuff->depth != 1)
79705b261ecSmrg            return BadMatch;
79805b261ecSmrg        length = PixmapBytePad(stuff->totalWidth, 1);
79905b261ecSmrg    }
80005b261ecSmrg    else if (stuff->format == XYPixmap)
80105b261ecSmrg    {
80205b261ecSmrg        if (pDraw->depth != stuff->depth)
80305b261ecSmrg            return BadMatch;
80405b261ecSmrg        length = PixmapBytePad(stuff->totalWidth, 1);
80505b261ecSmrg	length *= stuff->depth;
80605b261ecSmrg    }
80705b261ecSmrg    else if (stuff->format == ZPixmap)
80805b261ecSmrg    {
80905b261ecSmrg        if (pDraw->depth != stuff->depth)
81005b261ecSmrg            return BadMatch;
81105b261ecSmrg        length = PixmapBytePad(stuff->totalWidth, stuff->depth);
81205b261ecSmrg    }
81305b261ecSmrg    else
81405b261ecSmrg    {
81505b261ecSmrg	client->errorValue = stuff->format;
81605b261ecSmrg        return BadValue;
81705b261ecSmrg    }
81805b261ecSmrg
81905b261ecSmrg    /*
82005b261ecSmrg     * There's a potential integer overflow in this check:
82105b261ecSmrg     * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight,
82205b261ecSmrg     *                client);
82305b261ecSmrg     * the version below ought to avoid it
82405b261ecSmrg     */
82505b261ecSmrg    if (stuff->totalHeight != 0 &&
82605b261ecSmrg	length > (shmdesc->size - stuff->offset)/stuff->totalHeight) {
82705b261ecSmrg	client->errorValue = stuff->totalWidth;
82805b261ecSmrg	return BadValue;
82905b261ecSmrg    }
83005b261ecSmrg    if (stuff->srcX > stuff->totalWidth)
83105b261ecSmrg    {
83205b261ecSmrg	client->errorValue = stuff->srcX;
83305b261ecSmrg	return BadValue;
83405b261ecSmrg    }
83505b261ecSmrg    if (stuff->srcY > stuff->totalHeight)
83605b261ecSmrg    {
83705b261ecSmrg	client->errorValue = stuff->srcY;
83805b261ecSmrg	return BadValue;
83905b261ecSmrg    }
84005b261ecSmrg    if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth)
84105b261ecSmrg    {
84205b261ecSmrg	client->errorValue = stuff->srcWidth;
84305b261ecSmrg	return BadValue;
84405b261ecSmrg    }
84505b261ecSmrg    if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight)
84605b261ecSmrg    {
84705b261ecSmrg	client->errorValue = stuff->srcHeight;
84805b261ecSmrg	return BadValue;
84905b261ecSmrg    }
85005b261ecSmrg
85105b261ecSmrg    if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) ||
85205b261ecSmrg	 ((stuff->format != ZPixmap) &&
85305b261ecSmrg	  (stuff->srcX < screenInfo.bitmapScanlinePad) &&
85405b261ecSmrg	  ((stuff->format == XYBitmap) ||
85505b261ecSmrg	   ((stuff->srcY == 0) &&
85605b261ecSmrg	    (stuff->srcHeight == stuff->totalHeight))))) &&
85705b261ecSmrg	((stuff->srcX + stuff->srcWidth) == stuff->totalWidth))
85805b261ecSmrg	(*pGC->ops->PutImage) (pDraw, pGC, stuff->depth,
85905b261ecSmrg			       stuff->dstX, stuff->dstY,
86005b261ecSmrg			       stuff->totalWidth, stuff->srcHeight,
86105b261ecSmrg			       stuff->srcX, stuff->format,
86205b261ecSmrg			       shmdesc->addr + stuff->offset +
86305b261ecSmrg			       (stuff->srcY * length));
86405b261ecSmrg    else
8654642e01fSmrg	doShmPutImage(pDraw, pGC, stuff->depth, stuff->format,
8664642e01fSmrg		      stuff->totalWidth, stuff->totalHeight,
8674642e01fSmrg		      stuff->srcX, stuff->srcY,
8684642e01fSmrg		      stuff->srcWidth, stuff->srcHeight,
8694642e01fSmrg		      stuff->dstX, stuff->dstY,
8704642e01fSmrg                      shmdesc->addr + stuff->offset);
87105b261ecSmrg
87205b261ecSmrg    if (stuff->sendEvent)
87305b261ecSmrg    {
87405b261ecSmrg	xShmCompletionEvent ev;
87505b261ecSmrg
87605b261ecSmrg	ev.type = ShmCompletionCode;
87705b261ecSmrg	ev.drawable = stuff->drawable;
87805b261ecSmrg	ev.sequenceNumber = client->sequence;
87905b261ecSmrg	ev.minorEvent = X_ShmPutImage;
88005b261ecSmrg	ev.majorEvent = ShmReqCode;
88105b261ecSmrg	ev.shmseg = stuff->shmseg;
88205b261ecSmrg	ev.offset = stuff->offset;
88305b261ecSmrg	WriteEventsToClient(client, 1, (xEvent *) &ev);
88405b261ecSmrg    }
88505b261ecSmrg
88605b261ecSmrg    return (client->noClientException);
88705b261ecSmrg}
88805b261ecSmrg
88905b261ecSmrg
89005b261ecSmrg
89105b261ecSmrgstatic int
8924642e01fSmrgProcShmGetImage(ClientPtr client)
89305b261ecSmrg{
89405b261ecSmrg    DrawablePtr		pDraw;
89505b261ecSmrg    long		lenPer = 0, length;
89605b261ecSmrg    Mask		plane = 0;
89705b261ecSmrg    xShmGetImageReply	xgi;
89805b261ecSmrg    ShmDescPtr		shmdesc;
89905b261ecSmrg    int			n, rc;
90005b261ecSmrg
90105b261ecSmrg    REQUEST(xShmGetImageReq);
90205b261ecSmrg
90305b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
90405b261ecSmrg    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap))
90505b261ecSmrg    {
90605b261ecSmrg	client->errorValue = stuff->format;
90705b261ecSmrg        return(BadValue);
90805b261ecSmrg    }
90905b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0,
9104642e01fSmrg			   DixReadAccess);
91105b261ecSmrg    if (rc != Success)
91205b261ecSmrg	return rc;
91305b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
91405b261ecSmrg    if (pDraw->type == DRAWABLE_WINDOW)
91505b261ecSmrg    {
91605b261ecSmrg      if( /* check for being viewable */
91705b261ecSmrg	 !((WindowPtr) pDraw)->realized ||
91805b261ecSmrg	  /* check for being on screen */
91905b261ecSmrg         pDraw->x + stuff->x < 0 ||
92005b261ecSmrg 	 pDraw->x + stuff->x + (int)stuff->width > pDraw->pScreen->width ||
92105b261ecSmrg         pDraw->y + stuff->y < 0 ||
92205b261ecSmrg         pDraw->y + stuff->y + (int)stuff->height > pDraw->pScreen->height ||
92305b261ecSmrg          /* check for being inside of border */
92405b261ecSmrg         stuff->x < - wBorderWidth((WindowPtr)pDraw) ||
92505b261ecSmrg         stuff->x + (int)stuff->width >
92605b261ecSmrg		wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width ||
92705b261ecSmrg         stuff->y < -wBorderWidth((WindowPtr)pDraw) ||
92805b261ecSmrg         stuff->y + (int)stuff->height >
92905b261ecSmrg		wBorderWidth((WindowPtr)pDraw) + (int)pDraw->height
93005b261ecSmrg        )
93105b261ecSmrg	    return(BadMatch);
93205b261ecSmrg	xgi.visual = wVisual(((WindowPtr)pDraw));
93305b261ecSmrg    }
93405b261ecSmrg    else
93505b261ecSmrg    {
93605b261ecSmrg	if (stuff->x < 0 ||
93705b261ecSmrg	    stuff->x+(int)stuff->width > pDraw->width ||
93805b261ecSmrg	    stuff->y < 0 ||
93905b261ecSmrg	    stuff->y+(int)stuff->height > pDraw->height
94005b261ecSmrg	    )
94105b261ecSmrg	    return(BadMatch);
94205b261ecSmrg	xgi.visual = None;
94305b261ecSmrg    }
94405b261ecSmrg    xgi.type = X_Reply;
94505b261ecSmrg    xgi.length = 0;
94605b261ecSmrg    xgi.sequenceNumber = client->sequence;
94705b261ecSmrg    xgi.depth = pDraw->depth;
94805b261ecSmrg    if(stuff->format == ZPixmap)
94905b261ecSmrg    {
95005b261ecSmrg	length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height;
95105b261ecSmrg    }
95205b261ecSmrg    else
95305b261ecSmrg    {
95405b261ecSmrg	lenPer = PixmapBytePad(stuff->width, 1) * stuff->height;
95505b261ecSmrg	plane = ((Mask)1) << (pDraw->depth - 1);
95605b261ecSmrg	/* only planes asked for */
95705b261ecSmrg	length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
95805b261ecSmrg    }
95905b261ecSmrg
96005b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
96105b261ecSmrg    xgi.size = length;
96205b261ecSmrg
96305b261ecSmrg    if (length == 0)
96405b261ecSmrg    {
96505b261ecSmrg	/* nothing to do */
96605b261ecSmrg    }
96705b261ecSmrg    else if (stuff->format == ZPixmap)
96805b261ecSmrg    {
96905b261ecSmrg	(*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y,
97005b261ecSmrg				    stuff->width, stuff->height,
97105b261ecSmrg				    stuff->format, stuff->planeMask,
97205b261ecSmrg				    shmdesc->addr + stuff->offset);
97305b261ecSmrg    }
97405b261ecSmrg    else
97505b261ecSmrg    {
97605b261ecSmrg
97705b261ecSmrg	length = stuff->offset;
97805b261ecSmrg        for (; plane; plane >>= 1)
97905b261ecSmrg	{
98005b261ecSmrg	    if (stuff->planeMask & plane)
98105b261ecSmrg	    {
98205b261ecSmrg		(*pDraw->pScreen->GetImage)(pDraw,
98305b261ecSmrg					    stuff->x, stuff->y,
98405b261ecSmrg					    stuff->width, stuff->height,
98505b261ecSmrg					    stuff->format, plane,
98605b261ecSmrg					    shmdesc->addr + length);
98705b261ecSmrg		length += lenPer;
98805b261ecSmrg	    }
98905b261ecSmrg	}
99005b261ecSmrg    }
99105b261ecSmrg
99205b261ecSmrg    if (client->swapped) {
99305b261ecSmrg    	swaps(&xgi.sequenceNumber, n);
99405b261ecSmrg    	swapl(&xgi.length, n);
99505b261ecSmrg	swapl(&xgi.visual, n);
99605b261ecSmrg	swapl(&xgi.size, n);
99705b261ecSmrg    }
99805b261ecSmrg    WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi);
99905b261ecSmrg
100005b261ecSmrg    return(client->noClientException);
100105b261ecSmrg}
100205b261ecSmrg
100305b261ecSmrgstatic PixmapPtr
10044642e01fSmrgfbShmCreatePixmap (ScreenPtr pScreen,
10054642e01fSmrg		   int width, int height, int depth, char *addr)
100605b261ecSmrg{
10074642e01fSmrg    PixmapPtr pPixmap;
100805b261ecSmrg
10094642e01fSmrg    pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0);
101005b261ecSmrg    if (!pPixmap)
101105b261ecSmrg	return NullPixmap;
101205b261ecSmrg
101305b261ecSmrg    if (!(*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth,
101405b261ecSmrg	    BitsPerPixel(depth), PixmapBytePad(width, depth), (pointer)addr)) {
101505b261ecSmrg	(*pScreen->DestroyPixmap)(pPixmap);
101605b261ecSmrg	return NullPixmap;
101705b261ecSmrg    }
101805b261ecSmrg    return pPixmap;
101905b261ecSmrg}
102005b261ecSmrg
102105b261ecSmrgstatic int
10224642e01fSmrgProcShmCreatePixmap(ClientPtr client)
102305b261ecSmrg{
102405b261ecSmrg    PixmapPtr pMap;
102505b261ecSmrg    DrawablePtr pDraw;
102605b261ecSmrg    DepthPtr pDepth;
10274642e01fSmrg    int i, rc;
102805b261ecSmrg    ShmDescPtr shmdesc;
102905b261ecSmrg    REQUEST(xShmCreatePixmapReq);
103005b261ecSmrg    unsigned int width, height, depth;
103105b261ecSmrg    unsigned long size;
103205b261ecSmrg
103305b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
103405b261ecSmrg    client->errorValue = stuff->pid;
103505b261ecSmrg    if (!sharedPixmaps)
103605b261ecSmrg	return BadImplementation;
103705b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->pid, client);
103805b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
10394642e01fSmrg			   DixGetAttrAccess);
104005b261ecSmrg    if (rc != Success)
104105b261ecSmrg	return rc;
104205b261ecSmrg
104305b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
104405b261ecSmrg
104505b261ecSmrg    width = stuff->width;
104605b261ecSmrg    height = stuff->height;
104705b261ecSmrg    depth = stuff->depth;
104805b261ecSmrg    if (!width || !height || !depth)
104905b261ecSmrg    {
105005b261ecSmrg	client->errorValue = 0;
105105b261ecSmrg        return BadValue;
105205b261ecSmrg    }
105305b261ecSmrg    if (width > 32767 || height > 32767)
105405b261ecSmrg	return BadAlloc;
105505b261ecSmrg
105605b261ecSmrg    if (stuff->depth != 1)
105705b261ecSmrg    {
105805b261ecSmrg        pDepth = pDraw->pScreen->allowedDepths;
105905b261ecSmrg        for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++)
106005b261ecSmrg	   if (pDepth->depth == stuff->depth)
106105b261ecSmrg               goto CreatePmap;
106205b261ecSmrg	client->errorValue = stuff->depth;
106305b261ecSmrg        return BadValue;
106405b261ecSmrg    }
106505b261ecSmrg
106605b261ecSmrgCreatePmap:
106705b261ecSmrg    size = PixmapBytePad(width, depth) * height;
106805b261ecSmrg    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
106905b261ecSmrg	if (size < width * height)
107005b261ecSmrg	    return BadAlloc;
107105b261ecSmrg    }
107205b261ecSmrg    /* thankfully, offset is unsigned */
107305b261ecSmrg    if (stuff->offset + size < size)
107405b261ecSmrg	return BadAlloc;
107505b261ecSmrg
107605b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
107705b261ecSmrg    pMap = (*shmFuncs[pDraw->pScreen->myNum]->CreatePixmap)(
107805b261ecSmrg			    pDraw->pScreen, stuff->width,
107905b261ecSmrg			    stuff->height, stuff->depth,
108005b261ecSmrg			    shmdesc->addr + stuff->offset);
108105b261ecSmrg    if (pMap)
108205b261ecSmrg    {
10834642e01fSmrg	rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP,
10844642e01fSmrg		      pMap, RT_NONE, NULL, DixCreateAccess);
10854642e01fSmrg	if (rc != Success) {
10864642e01fSmrg	    pDraw->pScreen->DestroyPixmap(pMap);
10874642e01fSmrg	    return rc;
10884642e01fSmrg	}
10894642e01fSmrg	dixSetPrivate(&pMap->devPrivates, shmPixmapPrivate, shmdesc);
109005b261ecSmrg	shmdesc->refcnt++;
109105b261ecSmrg	pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
109205b261ecSmrg	pMap->drawable.id = stuff->pid;
109305b261ecSmrg	if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap))
109405b261ecSmrg	{
109505b261ecSmrg	    return(client->noClientException);
109605b261ecSmrg	}
10974642e01fSmrg	pDraw->pScreen->DestroyPixmap(pMap);
109805b261ecSmrg    }
109905b261ecSmrg    return (BadAlloc);
110005b261ecSmrg}
110105b261ecSmrg
110205b261ecSmrgstatic int
11034642e01fSmrgProcShmDispatch (ClientPtr client)
110405b261ecSmrg{
110505b261ecSmrg    REQUEST(xReq);
110605b261ecSmrg    switch (stuff->data)
110705b261ecSmrg    {
110805b261ecSmrg    case X_ShmQueryVersion:
110905b261ecSmrg	return ProcShmQueryVersion(client);
111005b261ecSmrg    case X_ShmAttach:
111105b261ecSmrg	return ProcShmAttach(client);
111205b261ecSmrg    case X_ShmDetach:
111305b261ecSmrg	return ProcShmDetach(client);
111405b261ecSmrg    case X_ShmPutImage:
111505b261ecSmrg#ifdef PANORAMIX
111605b261ecSmrg        if ( !noPanoramiXExtension )
111705b261ecSmrg	   return ProcPanoramiXShmPutImage(client);
111805b261ecSmrg#endif
111905b261ecSmrg	return ProcShmPutImage(client);
112005b261ecSmrg    case X_ShmGetImage:
112105b261ecSmrg#ifdef PANORAMIX
112205b261ecSmrg        if ( !noPanoramiXExtension )
112305b261ecSmrg	   return ProcPanoramiXShmGetImage(client);
112405b261ecSmrg#endif
112505b261ecSmrg	return ProcShmGetImage(client);
112605b261ecSmrg    case X_ShmCreatePixmap:
112705b261ecSmrg#ifdef PANORAMIX
112805b261ecSmrg        if ( !noPanoramiXExtension )
112905b261ecSmrg	   return ProcPanoramiXShmCreatePixmap(client);
113005b261ecSmrg#endif
113105b261ecSmrg	   return ProcShmCreatePixmap(client);
113205b261ecSmrg    default:
113305b261ecSmrg	return BadRequest;
113405b261ecSmrg    }
113505b261ecSmrg}
113605b261ecSmrg
113705b261ecSmrgstatic void
11384642e01fSmrgSShmCompletionEvent(xShmCompletionEvent *from, xShmCompletionEvent *to)
113905b261ecSmrg{
114005b261ecSmrg    to->type = from->type;
114105b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
114205b261ecSmrg    cpswapl(from->drawable, to->drawable);
114305b261ecSmrg    cpswaps(from->minorEvent, to->minorEvent);
114405b261ecSmrg    to->majorEvent = from->majorEvent;
114505b261ecSmrg    cpswapl(from->shmseg, to->shmseg);
114605b261ecSmrg    cpswapl(from->offset, to->offset);
114705b261ecSmrg}
114805b261ecSmrg
114905b261ecSmrgstatic int
11504642e01fSmrgSProcShmQueryVersion(ClientPtr client)
115105b261ecSmrg{
11524642e01fSmrg    int n;
115305b261ecSmrg    REQUEST(xShmQueryVersionReq);
115405b261ecSmrg
115505b261ecSmrg    swaps(&stuff->length, n);
115605b261ecSmrg    return ProcShmQueryVersion(client);
115705b261ecSmrg}
115805b261ecSmrg
115905b261ecSmrgstatic int
11604642e01fSmrgSProcShmAttach(ClientPtr client)
116105b261ecSmrg{
11624642e01fSmrg    int n;
116305b261ecSmrg    REQUEST(xShmAttachReq);
116405b261ecSmrg    swaps(&stuff->length, n);
116505b261ecSmrg    REQUEST_SIZE_MATCH(xShmAttachReq);
116605b261ecSmrg    swapl(&stuff->shmseg, n);
116705b261ecSmrg    swapl(&stuff->shmid, n);
116805b261ecSmrg    return ProcShmAttach(client);
116905b261ecSmrg}
117005b261ecSmrg
117105b261ecSmrgstatic int
11724642e01fSmrgSProcShmDetach(ClientPtr client)
117305b261ecSmrg{
11744642e01fSmrg    int n;
117505b261ecSmrg    REQUEST(xShmDetachReq);
117605b261ecSmrg    swaps(&stuff->length, n);
117705b261ecSmrg    REQUEST_SIZE_MATCH(xShmDetachReq);
117805b261ecSmrg    swapl(&stuff->shmseg, n);
117905b261ecSmrg    return ProcShmDetach(client);
118005b261ecSmrg}
118105b261ecSmrg
118205b261ecSmrgstatic int
11834642e01fSmrgSProcShmPutImage(ClientPtr client)
118405b261ecSmrg{
11854642e01fSmrg    int n;
118605b261ecSmrg    REQUEST(xShmPutImageReq);
118705b261ecSmrg    swaps(&stuff->length, n);
118805b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
118905b261ecSmrg    swapl(&stuff->drawable, n);
119005b261ecSmrg    swapl(&stuff->gc, n);
119105b261ecSmrg    swaps(&stuff->totalWidth, n);
119205b261ecSmrg    swaps(&stuff->totalHeight, n);
119305b261ecSmrg    swaps(&stuff->srcX, n);
119405b261ecSmrg    swaps(&stuff->srcY, n);
119505b261ecSmrg    swaps(&stuff->srcWidth, n);
119605b261ecSmrg    swaps(&stuff->srcHeight, n);
119705b261ecSmrg    swaps(&stuff->dstX, n);
119805b261ecSmrg    swaps(&stuff->dstY, n);
119905b261ecSmrg    swapl(&stuff->shmseg, n);
120005b261ecSmrg    swapl(&stuff->offset, n);
120105b261ecSmrg    return ProcShmPutImage(client);
120205b261ecSmrg}
120305b261ecSmrg
120405b261ecSmrgstatic int
12054642e01fSmrgSProcShmGetImage(ClientPtr client)
120605b261ecSmrg{
12074642e01fSmrg    int n;
120805b261ecSmrg    REQUEST(xShmGetImageReq);
120905b261ecSmrg    swaps(&stuff->length, n);
121005b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
121105b261ecSmrg    swapl(&stuff->drawable, n);
121205b261ecSmrg    swaps(&stuff->x, n);
121305b261ecSmrg    swaps(&stuff->y, n);
121405b261ecSmrg    swaps(&stuff->width, n);
121505b261ecSmrg    swaps(&stuff->height, n);
121605b261ecSmrg    swapl(&stuff->planeMask, n);
121705b261ecSmrg    swapl(&stuff->shmseg, n);
121805b261ecSmrg    swapl(&stuff->offset, n);
121905b261ecSmrg    return ProcShmGetImage(client);
122005b261ecSmrg}
122105b261ecSmrg
122205b261ecSmrgstatic int
12234642e01fSmrgSProcShmCreatePixmap(ClientPtr client)
122405b261ecSmrg{
12254642e01fSmrg    int n;
122605b261ecSmrg    REQUEST(xShmCreatePixmapReq);
122705b261ecSmrg    swaps(&stuff->length, n);
122805b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
122905b261ecSmrg    swapl(&stuff->pid, n);
123005b261ecSmrg    swapl(&stuff->drawable, n);
123105b261ecSmrg    swaps(&stuff->width, n);
123205b261ecSmrg    swaps(&stuff->height, n);
123305b261ecSmrg    swapl(&stuff->shmseg, n);
123405b261ecSmrg    swapl(&stuff->offset, n);
123505b261ecSmrg    return ProcShmCreatePixmap(client);
123605b261ecSmrg}
123705b261ecSmrg
123805b261ecSmrgstatic int
12394642e01fSmrgSProcShmDispatch (ClientPtr client)
124005b261ecSmrg{
124105b261ecSmrg    REQUEST(xReq);
124205b261ecSmrg    switch (stuff->data)
124305b261ecSmrg    {
124405b261ecSmrg    case X_ShmQueryVersion:
124505b261ecSmrg	return SProcShmQueryVersion(client);
124605b261ecSmrg    case X_ShmAttach:
124705b261ecSmrg	return SProcShmAttach(client);
124805b261ecSmrg    case X_ShmDetach:
124905b261ecSmrg	return SProcShmDetach(client);
125005b261ecSmrg    case X_ShmPutImage:
125105b261ecSmrg	return SProcShmPutImage(client);
125205b261ecSmrg    case X_ShmGetImage:
125305b261ecSmrg	return SProcShmGetImage(client);
125405b261ecSmrg    case X_ShmCreatePixmap:
125505b261ecSmrg	return SProcShmCreatePixmap(client);
125605b261ecSmrg    default:
125705b261ecSmrg	return BadRequest;
125805b261ecSmrg    }
125905b261ecSmrg}
1260