shm.c revision 684baedf
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>
59684baedfSmrg#include <X11/extensions/shmproto.h>
6005b261ecSmrg#include <X11/Xfuncproto.h>
6105b261ecSmrg
624642e01fSmrg/* Needed for Solaris cross-zone shared memory extension */
634642e01fSmrg#ifdef HAVE_SHMCTL64
644642e01fSmrg#include <sys/ipc_impl.h>
654642e01fSmrg#define SHMSTAT(id, buf)	shmctl64(id, IPC_STAT64, buf)
664642e01fSmrg#define SHMSTAT_TYPE 		struct shmid_ds64
674642e01fSmrg#define SHMPERM_TYPE 		struct ipc_perm64
684642e01fSmrg#define SHM_PERM(buf) 		buf.shmx_perm
694642e01fSmrg#define SHM_SEGSZ(buf)		buf.shmx_segsz
704642e01fSmrg#define SHMPERM_UID(p)		p->ipcx_uid
714642e01fSmrg#define SHMPERM_CUID(p)		p->ipcx_cuid
724642e01fSmrg#define SHMPERM_GID(p)		p->ipcx_gid
734642e01fSmrg#define SHMPERM_CGID(p)		p->ipcx_cgid
744642e01fSmrg#define SHMPERM_MODE(p)		p->ipcx_mode
754642e01fSmrg#define SHMPERM_ZONEID(p)	p->ipcx_zoneid
764642e01fSmrg#else
774642e01fSmrg#define SHMSTAT(id, buf) 	shmctl(id, IPC_STAT, buf)
784642e01fSmrg#define SHMSTAT_TYPE 		struct shmid_ds
794642e01fSmrg#define SHMPERM_TYPE 		struct ipc_perm
804642e01fSmrg#define SHM_PERM(buf) 		buf.shm_perm
814642e01fSmrg#define SHM_SEGSZ(buf)		buf.shm_segsz
824642e01fSmrg#define SHMPERM_UID(p)		p->uid
834642e01fSmrg#define SHMPERM_CUID(p)		p->cuid
844642e01fSmrg#define SHMPERM_GID(p)		p->gid
854642e01fSmrg#define SHMPERM_CGID(p)		p->cgid
864642e01fSmrg#define SHMPERM_MODE(p)		p->mode
874642e01fSmrg#endif
884642e01fSmrg
8905b261ecSmrg#ifdef PANORAMIX
9005b261ecSmrg#include "panoramiX.h"
9105b261ecSmrg#include "panoramiXsrv.h"
9205b261ecSmrg#endif
9305b261ecSmrg
9405b261ecSmrg#include "modinit.h"
9505b261ecSmrg
9605b261ecSmrgtypedef struct _ShmDesc {
9705b261ecSmrg    struct _ShmDesc *next;
9805b261ecSmrg    int shmid;
9905b261ecSmrg    int refcnt;
10005b261ecSmrg    char *addr;
10105b261ecSmrg    Bool writable;
10205b261ecSmrg    unsigned long size;
10305b261ecSmrg} ShmDescRec, *ShmDescPtr;
10405b261ecSmrg
10505b261ecSmrgstatic PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS);
10605b261ecSmrgstatic int ShmDetachSegment(
10705b261ecSmrg    pointer		/* value */,
10805b261ecSmrg    XID			/* shmseg */
10905b261ecSmrg    );
11005b261ecSmrgstatic void ShmResetProc(
11105b261ecSmrg    ExtensionEntry *	/* extEntry */
11205b261ecSmrg    );
11305b261ecSmrgstatic void SShmCompletionEvent(
11405b261ecSmrg    xShmCompletionEvent * /* from */,
11505b261ecSmrg    xShmCompletionEvent * /* to */
11605b261ecSmrg    );
11705b261ecSmrg
11805b261ecSmrgstatic Bool ShmDestroyPixmap (PixmapPtr pPixmap);
11905b261ecSmrg
12005b261ecSmrgstatic DISPATCH_PROC(ProcShmAttach);
12105b261ecSmrgstatic DISPATCH_PROC(ProcShmCreatePixmap);
12205b261ecSmrgstatic DISPATCH_PROC(ProcShmDetach);
12305b261ecSmrgstatic DISPATCH_PROC(ProcShmDispatch);
12405b261ecSmrgstatic DISPATCH_PROC(ProcShmGetImage);
12505b261ecSmrgstatic DISPATCH_PROC(ProcShmPutImage);
12605b261ecSmrgstatic DISPATCH_PROC(ProcShmQueryVersion);
12705b261ecSmrgstatic DISPATCH_PROC(SProcShmAttach);
12805b261ecSmrgstatic DISPATCH_PROC(SProcShmCreatePixmap);
12905b261ecSmrgstatic DISPATCH_PROC(SProcShmDetach);
13005b261ecSmrgstatic DISPATCH_PROC(SProcShmDispatch);
13105b261ecSmrgstatic DISPATCH_PROC(SProcShmGetImage);
13205b261ecSmrgstatic DISPATCH_PROC(SProcShmPutImage);
13305b261ecSmrgstatic DISPATCH_PROC(SProcShmQueryVersion);
13405b261ecSmrg
13505b261ecSmrgstatic unsigned char ShmReqCode;
13605b261ecSmrg_X_EXPORT int ShmCompletionCode;
13705b261ecSmrg_X_EXPORT int BadShmSegCode;
13805b261ecSmrg_X_EXPORT RESTYPE ShmSegType;
13905b261ecSmrgstatic ShmDescPtr Shmsegs;
14005b261ecSmrgstatic Bool sharedPixmaps;
14105b261ecSmrgstatic ShmFuncsPtr shmFuncs[MAXSCREENS];
14205b261ecSmrgstatic DestroyPixmapProcPtr destroyPixmap[MAXSCREENS];
1434642e01fSmrgstatic int shmPixmapPrivateIndex;
1444642e01fSmrgstatic DevPrivateKey shmPixmapPrivate = &shmPixmapPrivateIndex;
1454642e01fSmrgstatic ShmFuncs miFuncs = {NULL, NULL};
1464642e01fSmrgstatic ShmFuncs fbFuncs = {fbShmCreatePixmap, NULL};
14705b261ecSmrg
14805b261ecSmrg#define VERIFY_SHMSEG(shmseg,shmdesc,client) \
14905b261ecSmrg{ \
15005b261ecSmrg    shmdesc = (ShmDescPtr)LookupIDByType(shmseg, ShmSegType); \
15105b261ecSmrg    if (!shmdesc) \
15205b261ecSmrg    { \
15305b261ecSmrg	client->errorValue = shmseg; \
15405b261ecSmrg	return BadShmSegCode; \
15505b261ecSmrg    } \
15605b261ecSmrg}
15705b261ecSmrg
15805b261ecSmrg#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \
15905b261ecSmrg{ \
16005b261ecSmrg    VERIFY_SHMSEG(shmseg, shmdesc, client); \
16105b261ecSmrg    if ((offset & 3) || (offset > shmdesc->size)) \
16205b261ecSmrg    { \
16305b261ecSmrg	client->errorValue = offset; \
16405b261ecSmrg	return BadValue; \
16505b261ecSmrg    } \
16605b261ecSmrg    if (needwrite && !shmdesc->writable) \
16705b261ecSmrg	return BadAccess; \
16805b261ecSmrg}
16905b261ecSmrg
17005b261ecSmrg#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \
17105b261ecSmrg{ \
17205b261ecSmrg    if ((offset + len) > shmdesc->size) \
17305b261ecSmrg    { \
17405b261ecSmrg	return BadAccess; \
17505b261ecSmrg    } \
17605b261ecSmrg}
17705b261ecSmrg
17805b261ecSmrg
17905b261ecSmrg#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
18005b261ecSmrg#include <sys/signal.h>
18105b261ecSmrg
18205b261ecSmrgstatic Bool badSysCall = FALSE;
18305b261ecSmrg
18405b261ecSmrgstatic void
1854642e01fSmrgSigSysHandler(int signo)
18605b261ecSmrg{
18705b261ecSmrg    badSysCall = TRUE;
18805b261ecSmrg}
18905b261ecSmrg
1904642e01fSmrgstatic Bool CheckForShmSyscall(void)
19105b261ecSmrg{
19205b261ecSmrg    void (*oldHandler)();
19305b261ecSmrg    int shmid = -1;
19405b261ecSmrg
19505b261ecSmrg    /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
19605b261ecSmrg    oldHandler = signal(SIGSYS, SigSysHandler);
19705b261ecSmrg
19805b261ecSmrg    badSysCall = FALSE;
19905b261ecSmrg    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
20005b261ecSmrg
20105b261ecSmrg    if (shmid != -1)
20205b261ecSmrg    {
20305b261ecSmrg        /* Successful allocation - clean up */
20405b261ecSmrg	shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL);
20505b261ecSmrg    }
20605b261ecSmrg    else
20705b261ecSmrg    {
20805b261ecSmrg        /* Allocation failed */
20905b261ecSmrg        badSysCall = TRUE;
21005b261ecSmrg    }
21105b261ecSmrg    signal(SIGSYS, oldHandler);
21205b261ecSmrg    return(!badSysCall);
21305b261ecSmrg}
21405b261ecSmrg
21505b261ecSmrg#define MUST_CHECK_FOR_SHM_SYSCALL
21605b261ecSmrg
21705b261ecSmrg#endif
21805b261ecSmrg
21905b261ecSmrgvoid
22005b261ecSmrgShmExtensionInit(INITARGS)
22105b261ecSmrg{
22205b261ecSmrg    ExtensionEntry *extEntry;
22305b261ecSmrg    int i;
22405b261ecSmrg
22505b261ecSmrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL
22605b261ecSmrg    if (!CheckForShmSyscall())
22705b261ecSmrg    {
22805b261ecSmrg	ErrorF("MIT-SHM extension disabled due to lack of kernel support\n");
22905b261ecSmrg	return;
23005b261ecSmrg    }
23105b261ecSmrg#endif
23205b261ecSmrg
23305b261ecSmrg    sharedPixmaps = xFalse;
23405b261ecSmrg    {
23505b261ecSmrg      sharedPixmaps = xTrue;
23605b261ecSmrg      for (i = 0; i < screenInfo.numScreens; i++)
23705b261ecSmrg      {
23805b261ecSmrg	if (!shmFuncs[i])
23905b261ecSmrg	    shmFuncs[i] = &miFuncs;
24005b261ecSmrg	if (!shmFuncs[i]->CreatePixmap)
24105b261ecSmrg	    sharedPixmaps = xFalse;
24205b261ecSmrg      }
24305b261ecSmrg      if (sharedPixmaps)
24405b261ecSmrg	for (i = 0; i < screenInfo.numScreens; i++)
24505b261ecSmrg	{
24605b261ecSmrg	    destroyPixmap[i] = screenInfo.screens[i]->DestroyPixmap;
24705b261ecSmrg	    screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap;
24805b261ecSmrg	}
24905b261ecSmrg    }
25005b261ecSmrg    ShmSegType = CreateNewResourceType(ShmDetachSegment);
25105b261ecSmrg    if (ShmSegType &&
25205b261ecSmrg	(extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors,
25305b261ecSmrg				 ProcShmDispatch, SProcShmDispatch,
25405b261ecSmrg				 ShmResetProc, StandardMinorOpcode)))
25505b261ecSmrg    {
25605b261ecSmrg	ShmReqCode = (unsigned char)extEntry->base;
25705b261ecSmrg	ShmCompletionCode = extEntry->eventBase;
25805b261ecSmrg	BadShmSegCode = extEntry->errorBase;
25905b261ecSmrg	EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent;
26005b261ecSmrg    }
26105b261ecSmrg}
26205b261ecSmrg
26305b261ecSmrg/*ARGSUSED*/
26405b261ecSmrgstatic void
2654642e01fSmrgShmResetProc(ExtensionEntry *extEntry)
26605b261ecSmrg{
26705b261ecSmrg    int i;
26805b261ecSmrg
26905b261ecSmrg    for (i = 0; i < MAXSCREENS; i++)
27005b261ecSmrg    {
27105b261ecSmrg	shmFuncs[i] = (ShmFuncsPtr)NULL;
27205b261ecSmrg    }
27305b261ecSmrg}
27405b261ecSmrg
2754642e01fSmrg_X_EXPORT void
2764642e01fSmrgShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs)
27705b261ecSmrg{
27805b261ecSmrg    shmFuncs[pScreen->myNum] = funcs;
27905b261ecSmrg}
28005b261ecSmrg
28105b261ecSmrgstatic Bool
28205b261ecSmrgShmDestroyPixmap (PixmapPtr pPixmap)
28305b261ecSmrg{
28405b261ecSmrg    ScreenPtr	    pScreen = pPixmap->drawable.pScreen;
28505b261ecSmrg    Bool	    ret;
28605b261ecSmrg    if (pPixmap->refcnt == 1)
28705b261ecSmrg    {
28805b261ecSmrg	ShmDescPtr  shmdesc;
2894642e01fSmrg	shmdesc = (ShmDescPtr)dixLookupPrivate(&pPixmap->devPrivates,
2904642e01fSmrg					       shmPixmapPrivate);
29105b261ecSmrg	if (shmdesc)
29205b261ecSmrg	    ShmDetachSegment ((pointer) shmdesc, pPixmap->drawable.id);
29305b261ecSmrg    }
29405b261ecSmrg
29505b261ecSmrg    pScreen->DestroyPixmap = destroyPixmap[pScreen->myNum];
29605b261ecSmrg    ret = (*pScreen->DestroyPixmap) (pPixmap);
29705b261ecSmrg    destroyPixmap[pScreen->myNum] = pScreen->DestroyPixmap;
29805b261ecSmrg    pScreen->DestroyPixmap = ShmDestroyPixmap;
29905b261ecSmrg    return ret;
30005b261ecSmrg}
30105b261ecSmrg
3024642e01fSmrg_X_EXPORT void
3034642e01fSmrgShmRegisterFbFuncs(ScreenPtr pScreen)
30405b261ecSmrg{
30505b261ecSmrg    shmFuncs[pScreen->myNum] = &fbFuncs;
30605b261ecSmrg}
30705b261ecSmrg
30805b261ecSmrgstatic int
3094642e01fSmrgProcShmQueryVersion(ClientPtr client)
31005b261ecSmrg{
31105b261ecSmrg    xShmQueryVersionReply rep;
3124642e01fSmrg    int n;
31305b261ecSmrg
31405b261ecSmrg    REQUEST_SIZE_MATCH(xShmQueryVersionReq);
31505b261ecSmrg    rep.type = X_Reply;
31605b261ecSmrg    rep.length = 0;
31705b261ecSmrg    rep.sequenceNumber = client->sequence;
31805b261ecSmrg    rep.sharedPixmaps = sharedPixmaps;
3194642e01fSmrg    rep.pixmapFormat = sharedPixmaps ? ZPixmap : 0;
32005b261ecSmrg    rep.majorVersion = SHM_MAJOR_VERSION;
32105b261ecSmrg    rep.minorVersion = SHM_MINOR_VERSION;
32205b261ecSmrg    rep.uid = geteuid();
32305b261ecSmrg    rep.gid = getegid();
32405b261ecSmrg    if (client->swapped) {
32505b261ecSmrg    	swaps(&rep.sequenceNumber, n);
32605b261ecSmrg    	swapl(&rep.length, n);
32705b261ecSmrg	swaps(&rep.majorVersion, n);
32805b261ecSmrg	swaps(&rep.minorVersion, n);
32905b261ecSmrg	swaps(&rep.uid, n);
33005b261ecSmrg	swaps(&rep.gid, n);
33105b261ecSmrg    }
33205b261ecSmrg    WriteToClient(client, sizeof(xShmQueryVersionReply), (char *)&rep);
33305b261ecSmrg    return (client->noClientException);
33405b261ecSmrg}
33505b261ecSmrg
33605b261ecSmrg/*
33705b261ecSmrg * Simulate the access() system call for a shared memory segement,
33805b261ecSmrg * using the credentials from the client if available
33905b261ecSmrg */
34005b261ecSmrgstatic int
3414642e01fSmrgshm_access(ClientPtr client, SHMPERM_TYPE *perm, int readonly)
34205b261ecSmrg{
34305b261ecSmrg    int uid, gid;
34405b261ecSmrg    mode_t mask;
3454642e01fSmrg    int uidset = 0, gidset = 0;
3464642e01fSmrg    LocalClientCredRec *lcc;
3474642e01fSmrg
3484642e01fSmrg    if (GetLocalClientCreds(client, &lcc) != -1) {
34905b261ecSmrg
3504642e01fSmrg	if (lcc->fieldsSet & LCC_UID_SET) {
3514642e01fSmrg	    uid = lcc->euid;
3524642e01fSmrg	    uidset = 1;
3534642e01fSmrg	}
3544642e01fSmrg	if (lcc->fieldsSet & LCC_GID_SET) {
3554642e01fSmrg	    gid = lcc->egid;
3564642e01fSmrg	    gidset = 1;
3574642e01fSmrg	}
3584642e01fSmrg
3594642e01fSmrg#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID)
3604642e01fSmrg	if ( ((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1)
3614642e01fSmrg	     || (lcc->zoneid != SHMPERM_ZONEID(perm))) {
3624642e01fSmrg		uidset = 0;
3634642e01fSmrg		gidset = 0;
36405b261ecSmrg	}
3654642e01fSmrg#endif
3664642e01fSmrg	FreeLocalClientCreds(lcc);
3674642e01fSmrg
3684642e01fSmrg	if (uidset) {
3694642e01fSmrg	    /* User id 0 always gets access */
3704642e01fSmrg	    if (uid == 0) {
3714642e01fSmrg		return 0;
3724642e01fSmrg	    }
3734642e01fSmrg	    /* Check the owner */
3744642e01fSmrg	    if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) {
3754642e01fSmrg		mask = S_IRUSR;
3764642e01fSmrg		if (!readonly) {
3774642e01fSmrg		    mask |= S_IWUSR;
3784642e01fSmrg		}
3794642e01fSmrg		return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
38005b261ecSmrg	    }
38105b261ecSmrg	}
3824642e01fSmrg
3834642e01fSmrg	if (gidset) {
3844642e01fSmrg	    /* Check the group */
3854642e01fSmrg	    if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) {
3864642e01fSmrg		mask = S_IRGRP;
3874642e01fSmrg		if (!readonly) {
3884642e01fSmrg		    mask |= S_IWGRP;
3894642e01fSmrg		}
3904642e01fSmrg		return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
39105b261ecSmrg	    }
39205b261ecSmrg	}
39305b261ecSmrg    }
39405b261ecSmrg    /* Otherwise, check everyone else */
39505b261ecSmrg    mask = S_IROTH;
39605b261ecSmrg    if (!readonly) {
39705b261ecSmrg	mask |= S_IWOTH;
39805b261ecSmrg    }
3994642e01fSmrg    return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
40005b261ecSmrg}
40105b261ecSmrg
40205b261ecSmrgstatic int
4034642e01fSmrgProcShmAttach(ClientPtr client)
40405b261ecSmrg{
4054642e01fSmrg    SHMSTAT_TYPE buf;
40605b261ecSmrg    ShmDescPtr shmdesc;
40705b261ecSmrg    REQUEST(xShmAttachReq);
40805b261ecSmrg
40905b261ecSmrg    REQUEST_SIZE_MATCH(xShmAttachReq);
41005b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
41105b261ecSmrg    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse))
41205b261ecSmrg    {
41305b261ecSmrg	client->errorValue = stuff->readOnly;
41405b261ecSmrg        return(BadValue);
41505b261ecSmrg    }
41605b261ecSmrg    for (shmdesc = Shmsegs;
41705b261ecSmrg	 shmdesc && (shmdesc->shmid != stuff->shmid);
41805b261ecSmrg	 shmdesc = shmdesc->next)
41905b261ecSmrg	;
42005b261ecSmrg    if (shmdesc)
42105b261ecSmrg    {
42205b261ecSmrg	if (!stuff->readOnly && !shmdesc->writable)
42305b261ecSmrg	    return BadAccess;
42405b261ecSmrg	shmdesc->refcnt++;
42505b261ecSmrg    }
42605b261ecSmrg    else
42705b261ecSmrg    {
42805b261ecSmrg	shmdesc = (ShmDescPtr) xalloc(sizeof(ShmDescRec));
42905b261ecSmrg	if (!shmdesc)
43005b261ecSmrg	    return BadAlloc;
43105b261ecSmrg	shmdesc->addr = shmat(stuff->shmid, 0,
43205b261ecSmrg			      stuff->readOnly ? SHM_RDONLY : 0);
43305b261ecSmrg	if ((shmdesc->addr == ((char *)-1)) ||
4344642e01fSmrg	    SHMSTAT(stuff->shmid, &buf))
43505b261ecSmrg	{
43605b261ecSmrg	    xfree(shmdesc);
43705b261ecSmrg	    return BadAccess;
43805b261ecSmrg	}
43905b261ecSmrg
44005b261ecSmrg	/* The attach was performed with root privs. We must
44105b261ecSmrg	 * do manual checking of access rights for the credentials
44205b261ecSmrg	 * of the client */
44305b261ecSmrg
4444642e01fSmrg	if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) {
44505b261ecSmrg	    shmdt(shmdesc->addr);
44605b261ecSmrg	    xfree(shmdesc);
44705b261ecSmrg	    return BadAccess;
44805b261ecSmrg	}
44905b261ecSmrg
45005b261ecSmrg	shmdesc->shmid = stuff->shmid;
45105b261ecSmrg	shmdesc->refcnt = 1;
45205b261ecSmrg	shmdesc->writable = !stuff->readOnly;
4534642e01fSmrg	shmdesc->size = SHM_SEGSZ(buf);
45405b261ecSmrg	shmdesc->next = Shmsegs;
45505b261ecSmrg	Shmsegs = shmdesc;
45605b261ecSmrg    }
45705b261ecSmrg    if (!AddResource(stuff->shmseg, ShmSegType, (pointer)shmdesc))
45805b261ecSmrg	return BadAlloc;
45905b261ecSmrg    return(client->noClientException);
46005b261ecSmrg}
46105b261ecSmrg
46205b261ecSmrg/*ARGSUSED*/
46305b261ecSmrgstatic int
4644642e01fSmrgShmDetachSegment(pointer value, /* must conform to DeleteType */
4654642e01fSmrg		 XID shmseg)
46605b261ecSmrg{
46705b261ecSmrg    ShmDescPtr shmdesc = (ShmDescPtr)value;
46805b261ecSmrg    ShmDescPtr *prev;
46905b261ecSmrg
47005b261ecSmrg    if (--shmdesc->refcnt)
47105b261ecSmrg	return TRUE;
47205b261ecSmrg    shmdt(shmdesc->addr);
47305b261ecSmrg    for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next)
47405b261ecSmrg	;
47505b261ecSmrg    *prev = shmdesc->next;
47605b261ecSmrg    xfree(shmdesc);
47705b261ecSmrg    return Success;
47805b261ecSmrg}
47905b261ecSmrg
48005b261ecSmrgstatic int
4814642e01fSmrgProcShmDetach(ClientPtr client)
48205b261ecSmrg{
48305b261ecSmrg    ShmDescPtr shmdesc;
48405b261ecSmrg    REQUEST(xShmDetachReq);
48505b261ecSmrg
48605b261ecSmrg    REQUEST_SIZE_MATCH(xShmDetachReq);
48705b261ecSmrg    VERIFY_SHMSEG(stuff->shmseg, shmdesc, client);
48805b261ecSmrg    FreeResource(stuff->shmseg, RT_NONE);
48905b261ecSmrg    return(client->noClientException);
49005b261ecSmrg}
49105b261ecSmrg
4924642e01fSmrg/*
4934642e01fSmrg * If the given request doesn't exactly match PutImage's constraints,
4944642e01fSmrg * wrap the image in a scratch pixmap header and let CopyArea sort it out.
4954642e01fSmrg */
49605b261ecSmrgstatic void
4974642e01fSmrgdoShmPutImage(DrawablePtr dst, GCPtr pGC,
4984642e01fSmrg	      int depth, unsigned int format,
4994642e01fSmrg	      int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
5004642e01fSmrg	      char *data)
50105b261ecSmrg{
5024642e01fSmrg    PixmapPtr pPixmap;
5034642e01fSmrg
5044642e01fSmrg    pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth,
5054642e01fSmrg				     BitsPerPixel(depth),
5064642e01fSmrg				     PixmapBytePad(w, depth),
5074642e01fSmrg				     data);
5084642e01fSmrg    if (!pPixmap)
50905b261ecSmrg	return;
5104642e01fSmrg    pGC->ops->CopyArea((DrawablePtr)pPixmap, dst, pGC, sx, sy, sw, sh, dx, dy);
5114642e01fSmrg    FreeScratchPixmapHeader(pPixmap);
51205b261ecSmrg}
51305b261ecSmrg
51405b261ecSmrg#ifdef PANORAMIX
51505b261ecSmrgstatic int
5164642e01fSmrgProcPanoramiXShmPutImage(ClientPtr client)
51705b261ecSmrg{
51805b261ecSmrg    int			 j, result = 0, orig_x, orig_y;
51905b261ecSmrg    PanoramiXRes	*draw, *gc;
52005b261ecSmrg    Bool		 sendEvent, isRoot;
52105b261ecSmrg
52205b261ecSmrg    REQUEST(xShmPutImageReq);
52305b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
52405b261ecSmrg
52505b261ecSmrg    if(!(draw = (PanoramiXRes *)SecurityLookupIDByClass(
52605b261ecSmrg                client, stuff->drawable, XRC_DRAWABLE, DixWriteAccess)))
52705b261ecSmrg        return BadDrawable;
52805b261ecSmrg
52905b261ecSmrg    if(!(gc = (PanoramiXRes *)SecurityLookupIDByType(
53005b261ecSmrg                client, stuff->gc, XRT_GC, DixReadAccess)))
53105b261ecSmrg        return BadGC;
53205b261ecSmrg
53305b261ecSmrg    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
53405b261ecSmrg
53505b261ecSmrg    orig_x = stuff->dstX;
53605b261ecSmrg    orig_y = stuff->dstY;
53705b261ecSmrg    sendEvent = stuff->sendEvent;
53805b261ecSmrg    stuff->sendEvent = 0;
53905b261ecSmrg    FOR_NSCREENS(j) {
54005b261ecSmrg	if(!j) stuff->sendEvent = sendEvent;
54105b261ecSmrg	stuff->drawable = draw->info[j].id;
54205b261ecSmrg	stuff->gc = gc->info[j].id;
54305b261ecSmrg	if (isRoot) {
54405b261ecSmrg	    stuff->dstX = orig_x - panoramiXdataPtr[j].x;
54505b261ecSmrg	    stuff->dstY = orig_y - panoramiXdataPtr[j].y;
54605b261ecSmrg	}
54705b261ecSmrg	result = ProcShmPutImage(client);
54805b261ecSmrg	if(result != client->noClientException) break;
54905b261ecSmrg    }
55005b261ecSmrg    return(result);
55105b261ecSmrg}
55205b261ecSmrg
55305b261ecSmrgstatic int
55405b261ecSmrgProcPanoramiXShmGetImage(ClientPtr client)
55505b261ecSmrg{
55605b261ecSmrg    PanoramiXRes	*draw;
55705b261ecSmrg    DrawablePtr 	drawables[MAXSCREENS];
55805b261ecSmrg    DrawablePtr 	pDraw;
55905b261ecSmrg    xShmGetImageReply	xgi;
56005b261ecSmrg    ShmDescPtr		shmdesc;
56105b261ecSmrg    int         	i, x, y, w, h, format, rc;
56205b261ecSmrg    Mask		plane = 0, planemask;
56305b261ecSmrg    long		lenPer = 0, length, widthBytesLine;
56405b261ecSmrg    Bool		isRoot;
56505b261ecSmrg
56605b261ecSmrg    REQUEST(xShmGetImageReq);
56705b261ecSmrg
56805b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
56905b261ecSmrg
57005b261ecSmrg    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
57105b261ecSmrg	client->errorValue = stuff->format;
57205b261ecSmrg        return(BadValue);
57305b261ecSmrg    }
57405b261ecSmrg
57505b261ecSmrg    if(!(draw = (PanoramiXRes *)SecurityLookupIDByClass(
57605b261ecSmrg		client, stuff->drawable, XRC_DRAWABLE, DixWriteAccess)))
57705b261ecSmrg	return BadDrawable;
57805b261ecSmrg
57905b261ecSmrg    if (draw->type == XRT_PIXMAP)
58005b261ecSmrg	return ProcShmGetImage(client);
58105b261ecSmrg
58205b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0,
5834642e01fSmrg			   DixReadAccess);
58405b261ecSmrg    if (rc != Success)
58505b261ecSmrg	return rc;
58605b261ecSmrg
58705b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
58805b261ecSmrg
58905b261ecSmrg    x = stuff->x;
59005b261ecSmrg    y = stuff->y;
59105b261ecSmrg    w = stuff->width;
59205b261ecSmrg    h = stuff->height;
59305b261ecSmrg    format = stuff->format;
59405b261ecSmrg    planemask = stuff->planeMask;
59505b261ecSmrg
59605b261ecSmrg    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
59705b261ecSmrg
59805b261ecSmrg    if(isRoot) {
59905b261ecSmrg      if( /* check for being onscreen */
60005b261ecSmrg	x < 0 || x + w > PanoramiXPixWidth ||
60105b261ecSmrg	y < 0 || y + h > PanoramiXPixHeight )
60205b261ecSmrg	    return(BadMatch);
60305b261ecSmrg    } else {
60405b261ecSmrg      if( /* check for being onscreen */
60505b261ecSmrg	panoramiXdataPtr[0].x + pDraw->x + x < 0 ||
60605b261ecSmrg	panoramiXdataPtr[0].x + pDraw->x + x + w > PanoramiXPixWidth ||
60705b261ecSmrg        panoramiXdataPtr[0].y + pDraw->y + y < 0 ||
60805b261ecSmrg	panoramiXdataPtr[0].y + pDraw->y + y + h > PanoramiXPixHeight ||
60905b261ecSmrg	 /* check for being inside of border */
61005b261ecSmrg       	x < - wBorderWidth((WindowPtr)pDraw) ||
61105b261ecSmrg	x + w > wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width ||
61205b261ecSmrg	y < -wBorderWidth((WindowPtr)pDraw) ||
61305b261ecSmrg	y + h > wBorderWidth ((WindowPtr)pDraw) + (int)pDraw->height)
61405b261ecSmrg	    return(BadMatch);
61505b261ecSmrg    }
61605b261ecSmrg
61705b261ecSmrg    drawables[0] = pDraw;
61805b261ecSmrg    for(i = 1; i < PanoramiXNumScreens; i++) {
61905b261ecSmrg	rc = dixLookupDrawable(drawables+i, draw->info[i].id, client, 0,
6204642e01fSmrg			       DixReadAccess);
62105b261ecSmrg	if (rc != Success)
62205b261ecSmrg	    return rc;
62305b261ecSmrg    }
62405b261ecSmrg
62505b261ecSmrg    xgi.visual = wVisual(((WindowPtr)pDraw));
62605b261ecSmrg    xgi.type = X_Reply;
62705b261ecSmrg    xgi.length = 0;
62805b261ecSmrg    xgi.sequenceNumber = client->sequence;
62905b261ecSmrg    xgi.depth = pDraw->depth;
63005b261ecSmrg
63105b261ecSmrg    if(format == ZPixmap) {
63205b261ecSmrg	widthBytesLine = PixmapBytePad(w, pDraw->depth);
63305b261ecSmrg	length = widthBytesLine * h;
63405b261ecSmrg    } else {
63505b261ecSmrg	widthBytesLine = PixmapBytePad(w, 1);
63605b261ecSmrg	lenPer = widthBytesLine * h;
63705b261ecSmrg	plane = ((Mask)1) << (pDraw->depth - 1);
63805b261ecSmrg	length = lenPer * Ones(planemask & (plane | (plane - 1)));
63905b261ecSmrg    }
64005b261ecSmrg
64105b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
64205b261ecSmrg    xgi.size = length;
64305b261ecSmrg
64405b261ecSmrg    if (length == 0) {/* nothing to do */ }
64505b261ecSmrg    else if (format == ZPixmap) {
64605b261ecSmrg	    XineramaGetImageData(drawables, x, y, w, h, format, planemask,
64705b261ecSmrg					shmdesc->addr + stuff->offset,
64805b261ecSmrg					widthBytesLine, isRoot);
64905b261ecSmrg    } else {
65005b261ecSmrg
65105b261ecSmrg	length = stuff->offset;
65205b261ecSmrg        for (; plane; plane >>= 1) {
65305b261ecSmrg	    if (planemask & plane) {
65405b261ecSmrg		XineramaGetImageData(drawables, x, y, w, h,
65505b261ecSmrg				     format, plane, shmdesc->addr + length,
65605b261ecSmrg				     widthBytesLine, isRoot);
65705b261ecSmrg		length += lenPer;
65805b261ecSmrg	    }
65905b261ecSmrg	}
66005b261ecSmrg    }
66105b261ecSmrg
66205b261ecSmrg    if (client->swapped) {
6634642e01fSmrg	int n;
66405b261ecSmrg    	swaps(&xgi.sequenceNumber, n);
66505b261ecSmrg    	swapl(&xgi.length, n);
66605b261ecSmrg	swapl(&xgi.visual, n);
66705b261ecSmrg	swapl(&xgi.size, n);
66805b261ecSmrg    }
66905b261ecSmrg    WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi);
67005b261ecSmrg
67105b261ecSmrg    return(client->noClientException);
67205b261ecSmrg}
67305b261ecSmrg
67405b261ecSmrgstatic int
6754642e01fSmrgProcPanoramiXShmCreatePixmap(ClientPtr client)
67605b261ecSmrg{
67705b261ecSmrg    ScreenPtr pScreen = NULL;
67805b261ecSmrg    PixmapPtr pMap = NULL;
67905b261ecSmrg    DrawablePtr pDraw;
68005b261ecSmrg    DepthPtr pDepth;
68105b261ecSmrg    int i, j, result, rc;
68205b261ecSmrg    ShmDescPtr shmdesc;
68305b261ecSmrg    REQUEST(xShmCreatePixmapReq);
68405b261ecSmrg    unsigned int width, height, depth;
68505b261ecSmrg    unsigned long size;
68605b261ecSmrg    PanoramiXRes *newPix;
68705b261ecSmrg
68805b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
68905b261ecSmrg    client->errorValue = stuff->pid;
69005b261ecSmrg    if (!sharedPixmaps)
69105b261ecSmrg	return BadImplementation;
69205b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->pid, client);
69305b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
6944642e01fSmrg			   DixGetAttrAccess);
69505b261ecSmrg    if (rc != Success)
69605b261ecSmrg	return rc;
69705b261ecSmrg
69805b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
69905b261ecSmrg
70005b261ecSmrg    width = stuff->width;
70105b261ecSmrg    height = stuff->height;
70205b261ecSmrg    depth = stuff->depth;
70305b261ecSmrg    if (!width || !height || !depth)
70405b261ecSmrg    {
70505b261ecSmrg	client->errorValue = 0;
70605b261ecSmrg        return BadValue;
70705b261ecSmrg    }
70805b261ecSmrg    if (width > 32767 || height > 32767)
70905b261ecSmrg        return BadAlloc;
71005b261ecSmrg
71105b261ecSmrg    if (stuff->depth != 1)
71205b261ecSmrg    {
71305b261ecSmrg        pDepth = pDraw->pScreen->allowedDepths;
71405b261ecSmrg        for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++)
71505b261ecSmrg	   if (pDepth->depth == stuff->depth)
71605b261ecSmrg               goto CreatePmap;
71705b261ecSmrg	client->errorValue = stuff->depth;
71805b261ecSmrg        return BadValue;
71905b261ecSmrg    }
72005b261ecSmrg
72105b261ecSmrgCreatePmap:
72205b261ecSmrg    size = PixmapBytePad(width, depth) * height;
72305b261ecSmrg    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
72405b261ecSmrg        if (size < width * height)
72505b261ecSmrg            return BadAlloc;
72605b261ecSmrg    }
72705b261ecSmrg    /* thankfully, offset is unsigned */
72805b261ecSmrg    if (stuff->offset + size < size)
72905b261ecSmrg	return BadAlloc;
73005b261ecSmrg
73105b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
73205b261ecSmrg
73305b261ecSmrg    if(!(newPix = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes))))
73405b261ecSmrg	return BadAlloc;
73505b261ecSmrg
73605b261ecSmrg    newPix->type = XRT_PIXMAP;
73705b261ecSmrg    newPix->u.pix.shared = TRUE;
73805b261ecSmrg    newPix->info[0].id = stuff->pid;
73905b261ecSmrg    for(j = 1; j < PanoramiXNumScreens; j++)
74005b261ecSmrg	newPix->info[j].id = FakeClientID(client->index);
74105b261ecSmrg
74205b261ecSmrg    result = (client->noClientException);
74305b261ecSmrg
74405b261ecSmrg    FOR_NSCREENS(j) {
74505b261ecSmrg	pScreen = screenInfo.screens[j];
74605b261ecSmrg
74705b261ecSmrg	pMap = (*shmFuncs[j]->CreatePixmap)(pScreen,
74805b261ecSmrg				stuff->width, stuff->height, stuff->depth,
74905b261ecSmrg				shmdesc->addr + stuff->offset);
75005b261ecSmrg
75105b261ecSmrg	if (pMap) {
7524642e01fSmrg	    dixSetPrivate(&pMap->devPrivates, shmPixmapPrivate, shmdesc);
75305b261ecSmrg            shmdesc->refcnt++;
75405b261ecSmrg	    pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
75505b261ecSmrg	    pMap->drawable.id = newPix->info[j].id;
75605b261ecSmrg	    if (!AddResource(newPix->info[j].id, RT_PIXMAP, (pointer)pMap)) {
75705b261ecSmrg		(*pScreen->DestroyPixmap)(pMap);
75805b261ecSmrg		result = BadAlloc;
75905b261ecSmrg		break;
76005b261ecSmrg	    }
76105b261ecSmrg	} else {
76205b261ecSmrg	   result = BadAlloc;
76305b261ecSmrg	   break;
76405b261ecSmrg	}
76505b261ecSmrg    }
76605b261ecSmrg
76705b261ecSmrg    if(result == BadAlloc) {
76805b261ecSmrg	while(j--) {
76905b261ecSmrg	    (*pScreen->DestroyPixmap)(pMap);
77005b261ecSmrg	    FreeResource(newPix->info[j].id, RT_NONE);
77105b261ecSmrg	}
77205b261ecSmrg	xfree(newPix);
77305b261ecSmrg    } else
77405b261ecSmrg	AddResource(stuff->pid, XRT_PIXMAP, newPix);
77505b261ecSmrg
77605b261ecSmrg    return result;
77705b261ecSmrg}
77805b261ecSmrg
77905b261ecSmrg#endif
78005b261ecSmrg
78105b261ecSmrgstatic int
7824642e01fSmrgProcShmPutImage(ClientPtr client)
78305b261ecSmrg{
78405b261ecSmrg    GCPtr pGC;
78505b261ecSmrg    DrawablePtr pDraw;
78605b261ecSmrg    long length;
78705b261ecSmrg    ShmDescPtr shmdesc;
78805b261ecSmrg    REQUEST(xShmPutImageReq);
78905b261ecSmrg
79005b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
7914642e01fSmrg    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
79205b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client);
79305b261ecSmrg    if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse))
79405b261ecSmrg	return BadValue;
79505b261ecSmrg    if (stuff->format == XYBitmap)
79605b261ecSmrg    {
79705b261ecSmrg        if (stuff->depth != 1)
79805b261ecSmrg            return BadMatch;
79905b261ecSmrg        length = PixmapBytePad(stuff->totalWidth, 1);
80005b261ecSmrg    }
80105b261ecSmrg    else if (stuff->format == XYPixmap)
80205b261ecSmrg    {
80305b261ecSmrg        if (pDraw->depth != stuff->depth)
80405b261ecSmrg            return BadMatch;
80505b261ecSmrg        length = PixmapBytePad(stuff->totalWidth, 1);
80605b261ecSmrg	length *= stuff->depth;
80705b261ecSmrg    }
80805b261ecSmrg    else if (stuff->format == ZPixmap)
80905b261ecSmrg    {
81005b261ecSmrg        if (pDraw->depth != stuff->depth)
81105b261ecSmrg            return BadMatch;
81205b261ecSmrg        length = PixmapBytePad(stuff->totalWidth, stuff->depth);
81305b261ecSmrg    }
81405b261ecSmrg    else
81505b261ecSmrg    {
81605b261ecSmrg	client->errorValue = stuff->format;
81705b261ecSmrg        return BadValue;
81805b261ecSmrg    }
81905b261ecSmrg
82005b261ecSmrg    /*
82105b261ecSmrg     * There's a potential integer overflow in this check:
82205b261ecSmrg     * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight,
82305b261ecSmrg     *                client);
82405b261ecSmrg     * the version below ought to avoid it
82505b261ecSmrg     */
82605b261ecSmrg    if (stuff->totalHeight != 0 &&
82705b261ecSmrg	length > (shmdesc->size - stuff->offset)/stuff->totalHeight) {
82805b261ecSmrg	client->errorValue = stuff->totalWidth;
82905b261ecSmrg	return BadValue;
83005b261ecSmrg    }
83105b261ecSmrg    if (stuff->srcX > stuff->totalWidth)
83205b261ecSmrg    {
83305b261ecSmrg	client->errorValue = stuff->srcX;
83405b261ecSmrg	return BadValue;
83505b261ecSmrg    }
83605b261ecSmrg    if (stuff->srcY > stuff->totalHeight)
83705b261ecSmrg    {
83805b261ecSmrg	client->errorValue = stuff->srcY;
83905b261ecSmrg	return BadValue;
84005b261ecSmrg    }
84105b261ecSmrg    if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth)
84205b261ecSmrg    {
84305b261ecSmrg	client->errorValue = stuff->srcWidth;
84405b261ecSmrg	return BadValue;
84505b261ecSmrg    }
84605b261ecSmrg    if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight)
84705b261ecSmrg    {
84805b261ecSmrg	client->errorValue = stuff->srcHeight;
84905b261ecSmrg	return BadValue;
85005b261ecSmrg    }
85105b261ecSmrg
85205b261ecSmrg    if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) ||
85305b261ecSmrg	 ((stuff->format != ZPixmap) &&
85405b261ecSmrg	  (stuff->srcX < screenInfo.bitmapScanlinePad) &&
85505b261ecSmrg	  ((stuff->format == XYBitmap) ||
85605b261ecSmrg	   ((stuff->srcY == 0) &&
85705b261ecSmrg	    (stuff->srcHeight == stuff->totalHeight))))) &&
85805b261ecSmrg	((stuff->srcX + stuff->srcWidth) == stuff->totalWidth))
85905b261ecSmrg	(*pGC->ops->PutImage) (pDraw, pGC, stuff->depth,
86005b261ecSmrg			       stuff->dstX, stuff->dstY,
86105b261ecSmrg			       stuff->totalWidth, stuff->srcHeight,
86205b261ecSmrg			       stuff->srcX, stuff->format,
86305b261ecSmrg			       shmdesc->addr + stuff->offset +
86405b261ecSmrg			       (stuff->srcY * length));
86505b261ecSmrg    else
8664642e01fSmrg	doShmPutImage(pDraw, pGC, stuff->depth, stuff->format,
8674642e01fSmrg		      stuff->totalWidth, stuff->totalHeight,
8684642e01fSmrg		      stuff->srcX, stuff->srcY,
8694642e01fSmrg		      stuff->srcWidth, stuff->srcHeight,
8704642e01fSmrg		      stuff->dstX, stuff->dstY,
8714642e01fSmrg                      shmdesc->addr + stuff->offset);
87205b261ecSmrg
87305b261ecSmrg    if (stuff->sendEvent)
87405b261ecSmrg    {
87505b261ecSmrg	xShmCompletionEvent ev;
87605b261ecSmrg
87705b261ecSmrg	ev.type = ShmCompletionCode;
87805b261ecSmrg	ev.drawable = stuff->drawable;
87905b261ecSmrg	ev.sequenceNumber = client->sequence;
88005b261ecSmrg	ev.minorEvent = X_ShmPutImage;
88105b261ecSmrg	ev.majorEvent = ShmReqCode;
88205b261ecSmrg	ev.shmseg = stuff->shmseg;
88305b261ecSmrg	ev.offset = stuff->offset;
88405b261ecSmrg	WriteEventsToClient(client, 1, (xEvent *) &ev);
88505b261ecSmrg    }
88605b261ecSmrg
88705b261ecSmrg    return (client->noClientException);
88805b261ecSmrg}
88905b261ecSmrg
89005b261ecSmrg
89105b261ecSmrg
89205b261ecSmrgstatic int
8934642e01fSmrgProcShmGetImage(ClientPtr client)
89405b261ecSmrg{
89505b261ecSmrg    DrawablePtr		pDraw;
89605b261ecSmrg    long		lenPer = 0, length;
89705b261ecSmrg    Mask		plane = 0;
89805b261ecSmrg    xShmGetImageReply	xgi;
89905b261ecSmrg    ShmDescPtr		shmdesc;
90005b261ecSmrg    int			n, rc;
90105b261ecSmrg
90205b261ecSmrg    REQUEST(xShmGetImageReq);
90305b261ecSmrg
90405b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
90505b261ecSmrg    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap))
90605b261ecSmrg    {
90705b261ecSmrg	client->errorValue = stuff->format;
90805b261ecSmrg        return(BadValue);
90905b261ecSmrg    }
91005b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0,
9114642e01fSmrg			   DixReadAccess);
91205b261ecSmrg    if (rc != Success)
91305b261ecSmrg	return rc;
91405b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
91505b261ecSmrg    if (pDraw->type == DRAWABLE_WINDOW)
91605b261ecSmrg    {
91705b261ecSmrg      if( /* check for being viewable */
91805b261ecSmrg	 !((WindowPtr) pDraw)->realized ||
91905b261ecSmrg	  /* check for being on screen */
92005b261ecSmrg         pDraw->x + stuff->x < 0 ||
92105b261ecSmrg 	 pDraw->x + stuff->x + (int)stuff->width > pDraw->pScreen->width ||
92205b261ecSmrg         pDraw->y + stuff->y < 0 ||
92305b261ecSmrg         pDraw->y + stuff->y + (int)stuff->height > pDraw->pScreen->height ||
92405b261ecSmrg          /* check for being inside of border */
92505b261ecSmrg         stuff->x < - wBorderWidth((WindowPtr)pDraw) ||
92605b261ecSmrg         stuff->x + (int)stuff->width >
92705b261ecSmrg		wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width ||
92805b261ecSmrg         stuff->y < -wBorderWidth((WindowPtr)pDraw) ||
92905b261ecSmrg         stuff->y + (int)stuff->height >
93005b261ecSmrg		wBorderWidth((WindowPtr)pDraw) + (int)pDraw->height
93105b261ecSmrg        )
93205b261ecSmrg	    return(BadMatch);
93305b261ecSmrg	xgi.visual = wVisual(((WindowPtr)pDraw));
93405b261ecSmrg    }
93505b261ecSmrg    else
93605b261ecSmrg    {
93705b261ecSmrg	if (stuff->x < 0 ||
93805b261ecSmrg	    stuff->x+(int)stuff->width > pDraw->width ||
93905b261ecSmrg	    stuff->y < 0 ||
94005b261ecSmrg	    stuff->y+(int)stuff->height > pDraw->height
94105b261ecSmrg	    )
94205b261ecSmrg	    return(BadMatch);
94305b261ecSmrg	xgi.visual = None;
94405b261ecSmrg    }
94505b261ecSmrg    xgi.type = X_Reply;
94605b261ecSmrg    xgi.length = 0;
94705b261ecSmrg    xgi.sequenceNumber = client->sequence;
94805b261ecSmrg    xgi.depth = pDraw->depth;
94905b261ecSmrg    if(stuff->format == ZPixmap)
95005b261ecSmrg    {
95105b261ecSmrg	length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height;
95205b261ecSmrg    }
95305b261ecSmrg    else
95405b261ecSmrg    {
95505b261ecSmrg	lenPer = PixmapBytePad(stuff->width, 1) * stuff->height;
95605b261ecSmrg	plane = ((Mask)1) << (pDraw->depth - 1);
95705b261ecSmrg	/* only planes asked for */
95805b261ecSmrg	length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
95905b261ecSmrg    }
96005b261ecSmrg
96105b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
96205b261ecSmrg    xgi.size = length;
96305b261ecSmrg
96405b261ecSmrg    if (length == 0)
96505b261ecSmrg    {
96605b261ecSmrg	/* nothing to do */
96705b261ecSmrg    }
96805b261ecSmrg    else if (stuff->format == ZPixmap)
96905b261ecSmrg    {
97005b261ecSmrg	(*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y,
97105b261ecSmrg				    stuff->width, stuff->height,
97205b261ecSmrg				    stuff->format, stuff->planeMask,
97305b261ecSmrg				    shmdesc->addr + stuff->offset);
97405b261ecSmrg    }
97505b261ecSmrg    else
97605b261ecSmrg    {
97705b261ecSmrg
97805b261ecSmrg	length = stuff->offset;
97905b261ecSmrg        for (; plane; plane >>= 1)
98005b261ecSmrg	{
98105b261ecSmrg	    if (stuff->planeMask & plane)
98205b261ecSmrg	    {
98305b261ecSmrg		(*pDraw->pScreen->GetImage)(pDraw,
98405b261ecSmrg					    stuff->x, stuff->y,
98505b261ecSmrg					    stuff->width, stuff->height,
98605b261ecSmrg					    stuff->format, plane,
98705b261ecSmrg					    shmdesc->addr + length);
98805b261ecSmrg		length += lenPer;
98905b261ecSmrg	    }
99005b261ecSmrg	}
99105b261ecSmrg    }
99205b261ecSmrg
99305b261ecSmrg    if (client->swapped) {
99405b261ecSmrg    	swaps(&xgi.sequenceNumber, n);
99505b261ecSmrg    	swapl(&xgi.length, n);
99605b261ecSmrg	swapl(&xgi.visual, n);
99705b261ecSmrg	swapl(&xgi.size, n);
99805b261ecSmrg    }
99905b261ecSmrg    WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi);
100005b261ecSmrg
100105b261ecSmrg    return(client->noClientException);
100205b261ecSmrg}
100305b261ecSmrg
100405b261ecSmrgstatic PixmapPtr
10054642e01fSmrgfbShmCreatePixmap (ScreenPtr pScreen,
10064642e01fSmrg		   int width, int height, int depth, char *addr)
100705b261ecSmrg{
10084642e01fSmrg    PixmapPtr pPixmap;
100905b261ecSmrg
10104642e01fSmrg    pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0);
101105b261ecSmrg    if (!pPixmap)
101205b261ecSmrg	return NullPixmap;
101305b261ecSmrg
101405b261ecSmrg    if (!(*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth,
101505b261ecSmrg	    BitsPerPixel(depth), PixmapBytePad(width, depth), (pointer)addr)) {
101605b261ecSmrg	(*pScreen->DestroyPixmap)(pPixmap);
101705b261ecSmrg	return NullPixmap;
101805b261ecSmrg    }
101905b261ecSmrg    return pPixmap;
102005b261ecSmrg}
102105b261ecSmrg
102205b261ecSmrgstatic int
10234642e01fSmrgProcShmCreatePixmap(ClientPtr client)
102405b261ecSmrg{
102505b261ecSmrg    PixmapPtr pMap;
102605b261ecSmrg    DrawablePtr pDraw;
102705b261ecSmrg    DepthPtr pDepth;
10284642e01fSmrg    int i, rc;
102905b261ecSmrg    ShmDescPtr shmdesc;
103005b261ecSmrg    REQUEST(xShmCreatePixmapReq);
103105b261ecSmrg    unsigned int width, height, depth;
103205b261ecSmrg    unsigned long size;
103305b261ecSmrg
103405b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
103505b261ecSmrg    client->errorValue = stuff->pid;
103605b261ecSmrg    if (!sharedPixmaps)
103705b261ecSmrg	return BadImplementation;
103805b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->pid, client);
103905b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
10404642e01fSmrg			   DixGetAttrAccess);
104105b261ecSmrg    if (rc != Success)
104205b261ecSmrg	return rc;
104305b261ecSmrg
104405b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
104505b261ecSmrg
104605b261ecSmrg    width = stuff->width;
104705b261ecSmrg    height = stuff->height;
104805b261ecSmrg    depth = stuff->depth;
104905b261ecSmrg    if (!width || !height || !depth)
105005b261ecSmrg    {
105105b261ecSmrg	client->errorValue = 0;
105205b261ecSmrg        return BadValue;
105305b261ecSmrg    }
105405b261ecSmrg    if (width > 32767 || height > 32767)
105505b261ecSmrg	return BadAlloc;
105605b261ecSmrg
105705b261ecSmrg    if (stuff->depth != 1)
105805b261ecSmrg    {
105905b261ecSmrg        pDepth = pDraw->pScreen->allowedDepths;
106005b261ecSmrg        for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++)
106105b261ecSmrg	   if (pDepth->depth == stuff->depth)
106205b261ecSmrg               goto CreatePmap;
106305b261ecSmrg	client->errorValue = stuff->depth;
106405b261ecSmrg        return BadValue;
106505b261ecSmrg    }
106605b261ecSmrg
106705b261ecSmrgCreatePmap:
106805b261ecSmrg    size = PixmapBytePad(width, depth) * height;
106905b261ecSmrg    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
107005b261ecSmrg	if (size < width * height)
107105b261ecSmrg	    return BadAlloc;
107205b261ecSmrg    }
107305b261ecSmrg    /* thankfully, offset is unsigned */
107405b261ecSmrg    if (stuff->offset + size < size)
107505b261ecSmrg	return BadAlloc;
107605b261ecSmrg
107705b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
107805b261ecSmrg    pMap = (*shmFuncs[pDraw->pScreen->myNum]->CreatePixmap)(
107905b261ecSmrg			    pDraw->pScreen, stuff->width,
108005b261ecSmrg			    stuff->height, stuff->depth,
108105b261ecSmrg			    shmdesc->addr + stuff->offset);
108205b261ecSmrg    if (pMap)
108305b261ecSmrg    {
10844642e01fSmrg	rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP,
10854642e01fSmrg		      pMap, RT_NONE, NULL, DixCreateAccess);
10864642e01fSmrg	if (rc != Success) {
10874642e01fSmrg	    pDraw->pScreen->DestroyPixmap(pMap);
10884642e01fSmrg	    return rc;
10894642e01fSmrg	}
10904642e01fSmrg	dixSetPrivate(&pMap->devPrivates, shmPixmapPrivate, shmdesc);
109105b261ecSmrg	shmdesc->refcnt++;
109205b261ecSmrg	pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
109305b261ecSmrg	pMap->drawable.id = stuff->pid;
109405b261ecSmrg	if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap))
109505b261ecSmrg	{
109605b261ecSmrg	    return(client->noClientException);
109705b261ecSmrg	}
10984642e01fSmrg	pDraw->pScreen->DestroyPixmap(pMap);
109905b261ecSmrg    }
110005b261ecSmrg    return (BadAlloc);
110105b261ecSmrg}
110205b261ecSmrg
110305b261ecSmrgstatic int
11044642e01fSmrgProcShmDispatch (ClientPtr client)
110505b261ecSmrg{
110605b261ecSmrg    REQUEST(xReq);
110705b261ecSmrg    switch (stuff->data)
110805b261ecSmrg    {
110905b261ecSmrg    case X_ShmQueryVersion:
111005b261ecSmrg	return ProcShmQueryVersion(client);
111105b261ecSmrg    case X_ShmAttach:
111205b261ecSmrg	return ProcShmAttach(client);
111305b261ecSmrg    case X_ShmDetach:
111405b261ecSmrg	return ProcShmDetach(client);
111505b261ecSmrg    case X_ShmPutImage:
111605b261ecSmrg#ifdef PANORAMIX
111705b261ecSmrg        if ( !noPanoramiXExtension )
111805b261ecSmrg	   return ProcPanoramiXShmPutImage(client);
111905b261ecSmrg#endif
112005b261ecSmrg	return ProcShmPutImage(client);
112105b261ecSmrg    case X_ShmGetImage:
112205b261ecSmrg#ifdef PANORAMIX
112305b261ecSmrg        if ( !noPanoramiXExtension )
112405b261ecSmrg	   return ProcPanoramiXShmGetImage(client);
112505b261ecSmrg#endif
112605b261ecSmrg	return ProcShmGetImage(client);
112705b261ecSmrg    case X_ShmCreatePixmap:
112805b261ecSmrg#ifdef PANORAMIX
112905b261ecSmrg        if ( !noPanoramiXExtension )
113005b261ecSmrg	   return ProcPanoramiXShmCreatePixmap(client);
113105b261ecSmrg#endif
113205b261ecSmrg	   return ProcShmCreatePixmap(client);
113305b261ecSmrg    default:
113405b261ecSmrg	return BadRequest;
113505b261ecSmrg    }
113605b261ecSmrg}
113705b261ecSmrg
113805b261ecSmrgstatic void
11394642e01fSmrgSShmCompletionEvent(xShmCompletionEvent *from, xShmCompletionEvent *to)
114005b261ecSmrg{
114105b261ecSmrg    to->type = from->type;
114205b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
114305b261ecSmrg    cpswapl(from->drawable, to->drawable);
114405b261ecSmrg    cpswaps(from->minorEvent, to->minorEvent);
114505b261ecSmrg    to->majorEvent = from->majorEvent;
114605b261ecSmrg    cpswapl(from->shmseg, to->shmseg);
114705b261ecSmrg    cpswapl(from->offset, to->offset);
114805b261ecSmrg}
114905b261ecSmrg
115005b261ecSmrgstatic int
11514642e01fSmrgSProcShmQueryVersion(ClientPtr client)
115205b261ecSmrg{
11534642e01fSmrg    int n;
115405b261ecSmrg    REQUEST(xShmQueryVersionReq);
115505b261ecSmrg
115605b261ecSmrg    swaps(&stuff->length, n);
115705b261ecSmrg    return ProcShmQueryVersion(client);
115805b261ecSmrg}
115905b261ecSmrg
116005b261ecSmrgstatic int
11614642e01fSmrgSProcShmAttach(ClientPtr client)
116205b261ecSmrg{
11634642e01fSmrg    int n;
116405b261ecSmrg    REQUEST(xShmAttachReq);
116505b261ecSmrg    swaps(&stuff->length, n);
116605b261ecSmrg    REQUEST_SIZE_MATCH(xShmAttachReq);
116705b261ecSmrg    swapl(&stuff->shmseg, n);
116805b261ecSmrg    swapl(&stuff->shmid, n);
116905b261ecSmrg    return ProcShmAttach(client);
117005b261ecSmrg}
117105b261ecSmrg
117205b261ecSmrgstatic int
11734642e01fSmrgSProcShmDetach(ClientPtr client)
117405b261ecSmrg{
11754642e01fSmrg    int n;
117605b261ecSmrg    REQUEST(xShmDetachReq);
117705b261ecSmrg    swaps(&stuff->length, n);
117805b261ecSmrg    REQUEST_SIZE_MATCH(xShmDetachReq);
117905b261ecSmrg    swapl(&stuff->shmseg, n);
118005b261ecSmrg    return ProcShmDetach(client);
118105b261ecSmrg}
118205b261ecSmrg
118305b261ecSmrgstatic int
11844642e01fSmrgSProcShmPutImage(ClientPtr client)
118505b261ecSmrg{
11864642e01fSmrg    int n;
118705b261ecSmrg    REQUEST(xShmPutImageReq);
118805b261ecSmrg    swaps(&stuff->length, n);
118905b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
119005b261ecSmrg    swapl(&stuff->drawable, n);
119105b261ecSmrg    swapl(&stuff->gc, n);
119205b261ecSmrg    swaps(&stuff->totalWidth, n);
119305b261ecSmrg    swaps(&stuff->totalHeight, n);
119405b261ecSmrg    swaps(&stuff->srcX, n);
119505b261ecSmrg    swaps(&stuff->srcY, n);
119605b261ecSmrg    swaps(&stuff->srcWidth, n);
119705b261ecSmrg    swaps(&stuff->srcHeight, n);
119805b261ecSmrg    swaps(&stuff->dstX, n);
119905b261ecSmrg    swaps(&stuff->dstY, n);
120005b261ecSmrg    swapl(&stuff->shmseg, n);
120105b261ecSmrg    swapl(&stuff->offset, n);
120205b261ecSmrg    return ProcShmPutImage(client);
120305b261ecSmrg}
120405b261ecSmrg
120505b261ecSmrgstatic int
12064642e01fSmrgSProcShmGetImage(ClientPtr client)
120705b261ecSmrg{
12084642e01fSmrg    int n;
120905b261ecSmrg    REQUEST(xShmGetImageReq);
121005b261ecSmrg    swaps(&stuff->length, n);
121105b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
121205b261ecSmrg    swapl(&stuff->drawable, n);
121305b261ecSmrg    swaps(&stuff->x, n);
121405b261ecSmrg    swaps(&stuff->y, n);
121505b261ecSmrg    swaps(&stuff->width, n);
121605b261ecSmrg    swaps(&stuff->height, n);
121705b261ecSmrg    swapl(&stuff->planeMask, n);
121805b261ecSmrg    swapl(&stuff->shmseg, n);
121905b261ecSmrg    swapl(&stuff->offset, n);
122005b261ecSmrg    return ProcShmGetImage(client);
122105b261ecSmrg}
122205b261ecSmrg
122305b261ecSmrgstatic int
12244642e01fSmrgSProcShmCreatePixmap(ClientPtr client)
122505b261ecSmrg{
12264642e01fSmrg    int n;
122705b261ecSmrg    REQUEST(xShmCreatePixmapReq);
122805b261ecSmrg    swaps(&stuff->length, n);
122905b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
123005b261ecSmrg    swapl(&stuff->pid, n);
123105b261ecSmrg    swapl(&stuff->drawable, n);
123205b261ecSmrg    swaps(&stuff->width, n);
123305b261ecSmrg    swaps(&stuff->height, n);
123405b261ecSmrg    swapl(&stuff->shmseg, n);
123505b261ecSmrg    swapl(&stuff->offset, n);
123605b261ecSmrg    return ProcShmCreatePixmap(client);
123705b261ecSmrg}
123805b261ecSmrg
123905b261ecSmrgstatic int
12404642e01fSmrgSProcShmDispatch (ClientPtr client)
124105b261ecSmrg{
124205b261ecSmrg    REQUEST(xReq);
124305b261ecSmrg    switch (stuff->data)
124405b261ecSmrg    {
124505b261ecSmrg    case X_ShmQueryVersion:
124605b261ecSmrg	return SProcShmQueryVersion(client);
124705b261ecSmrg    case X_ShmAttach:
124805b261ecSmrg	return SProcShmAttach(client);
124905b261ecSmrg    case X_ShmDetach:
125005b261ecSmrg	return SProcShmDetach(client);
125105b261ecSmrg    case X_ShmPutImage:
125205b261ecSmrg	return SProcShmPutImage(client);
125305b261ecSmrg    case X_ShmGetImage:
125405b261ecSmrg	return SProcShmGetImage(client);
125505b261ecSmrg    case X_ShmCreatePixmap:
125605b261ecSmrg	return SProcShmCreatePixmap(client);
125705b261ecSmrg    default:
125805b261ecSmrg	return BadRequest;
125905b261ecSmrg    }
126005b261ecSmrg}
1261