shm.c revision f7df2e56
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#define SHM
3005b261ecSmrg
3105b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3205b261ecSmrg#include <dix-config.h>
3305b261ecSmrg#endif
3405b261ecSmrg
3505b261ecSmrg#include <sys/types.h>
3605b261ecSmrg#include <sys/ipc.h>
3705b261ecSmrg#include <sys/shm.h>
3805b261ecSmrg#include <unistd.h>
3905b261ecSmrg#include <sys/stat.h>
40f7df2e56Smrg#include <fcntl.h>
4105b261ecSmrg#include <X11/X.h>
4205b261ecSmrg#include <X11/Xproto.h>
4305b261ecSmrg#include "misc.h"
4405b261ecSmrg#include "os.h"
4505b261ecSmrg#include "dixstruct.h"
4605b261ecSmrg#include "resource.h"
4705b261ecSmrg#include "scrnintstr.h"
4805b261ecSmrg#include "windowstr.h"
4905b261ecSmrg#include "pixmapstr.h"
5005b261ecSmrg#include "gcstruct.h"
5105b261ecSmrg#include "extnsionst.h"
5205b261ecSmrg#include "servermd.h"
534642e01fSmrg#include "shmint.h"
544642e01fSmrg#include "xace.h"
55684baedfSmrg#include <X11/extensions/shmproto.h>
5605b261ecSmrg#include <X11/Xfuncproto.h>
57f7df2e56Smrg#include <sys/mman.h>
584202a189Smrg#include "protocol-versions.h"
59f7df2e56Smrg#include "busfault.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
93f7df2e56Smrg#include "extinit.h"
9405b261ecSmrg
954202a189Smrgtypedef struct _ShmScrPrivateRec {
964202a189Smrg    CloseScreenProcPtr CloseScreen;
974202a189Smrg    ShmFuncsPtr shmFuncs;
984202a189Smrg    DestroyPixmapProcPtr destroyPixmap;
994202a189Smrg} ShmScrPrivateRec;
1004202a189Smrg
10105b261ecSmrgstatic PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS);
102f7df2e56Smrgstatic int ShmDetachSegment(void *value, XID shmseg);
103f7df2e56Smrgstatic void ShmResetProc(ExtensionEntry *extEntry);
104f7df2e56Smrgstatic void SShmCompletionEvent(xShmCompletionEvent *from,
105f7df2e56Smrg                                xShmCompletionEvent *to);
10605b261ecSmrg
107f7df2e56Smrgstatic Bool ShmDestroyPixmap(PixmapPtr pPixmap);
10805b261ecSmrg
10905b261ecSmrgstatic unsigned char ShmReqCode;
1104202a189Smrgint ShmCompletionCode;
1114202a189Smrgint BadShmSegCode;
1124202a189SmrgRESTYPE ShmSegType;
11305b261ecSmrgstatic ShmDescPtr Shmsegs;
11405b261ecSmrgstatic Bool sharedPixmaps;
1154202a189Smrgstatic DevPrivateKeyRec shmScrPrivateKeyRec;
116f7df2e56Smrg
1174202a189Smrg#define shmScrPrivateKey (&shmScrPrivateKeyRec)
1184202a189Smrgstatic DevPrivateKeyRec shmPixmapPrivateKeyRec;
119f7df2e56Smrg
1204202a189Smrg#define shmPixmapPrivateKey (&shmPixmapPrivateKeyRec)
121f7df2e56Smrgstatic ShmFuncs miFuncs = { NULL, NULL };
122f7df2e56Smrgstatic ShmFuncs fbFuncs = { fbShmCreatePixmap, NULL };
12305b261ecSmrg
1244202a189Smrg#define ShmGetScreenPriv(s) ((ShmScrPrivateRec *)dixLookupPrivate(&(s)->devPrivates, shmScrPrivateKey))
1254202a189Smrg
12605b261ecSmrg#define VERIFY_SHMSEG(shmseg,shmdesc,client) \
12705b261ecSmrg{ \
128f7df2e56Smrg    int tmprc; \
129f7df2e56Smrg    tmprc = dixLookupResourceByType((void **)&(shmdesc), shmseg, ShmSegType, \
130f7df2e56Smrg                                    client, DixReadAccess); \
131f7df2e56Smrg    if (tmprc != Success) \
132f7df2e56Smrg	return tmprc; \
13305b261ecSmrg}
13405b261ecSmrg
13505b261ecSmrg#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \
13605b261ecSmrg{ \
13705b261ecSmrg    VERIFY_SHMSEG(shmseg, shmdesc, client); \
13805b261ecSmrg    if ((offset & 3) || (offset > shmdesc->size)) \
13905b261ecSmrg    { \
14005b261ecSmrg	client->errorValue = offset; \
14105b261ecSmrg	return BadValue; \
14205b261ecSmrg    } \
14305b261ecSmrg    if (needwrite && !shmdesc->writable) \
14405b261ecSmrg	return BadAccess; \
14505b261ecSmrg}
14605b261ecSmrg
14705b261ecSmrg#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \
14805b261ecSmrg{ \
14905b261ecSmrg    if ((offset + len) > shmdesc->size) \
15005b261ecSmrg    { \
15105b261ecSmrg	return BadAccess; \
15205b261ecSmrg    } \
15305b261ecSmrg}
15405b261ecSmrg
15505b261ecSmrg#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
15605b261ecSmrg#include <sys/signal.h>
15705b261ecSmrg
15805b261ecSmrgstatic Bool badSysCall = FALSE;
15905b261ecSmrg
16005b261ecSmrgstatic void
1614642e01fSmrgSigSysHandler(int signo)
16205b261ecSmrg{
16305b261ecSmrg    badSysCall = TRUE;
16405b261ecSmrg}
16505b261ecSmrg
166f7df2e56Smrgstatic Bool
167f7df2e56SmrgCheckForShmSyscall(void)
16805b261ecSmrg{
169f7df2e56Smrg    void (*oldHandler) (int);
17005b261ecSmrg    int shmid = -1;
17105b261ecSmrg
17205b261ecSmrg    /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
17305b261ecSmrg    oldHandler = signal(SIGSYS, SigSysHandler);
17405b261ecSmrg
17505b261ecSmrg    badSysCall = FALSE;
17605b261ecSmrg    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
17705b261ecSmrg
178f7df2e56Smrg    if (shmid != -1) {
17905b261ecSmrg        /* Successful allocation - clean up */
180f7df2e56Smrg        shmctl(shmid, IPC_RMID, NULL);
18105b261ecSmrg    }
182f7df2e56Smrg    else {
18305b261ecSmrg        /* Allocation failed */
18405b261ecSmrg        badSysCall = TRUE;
18505b261ecSmrg    }
18605b261ecSmrg    signal(SIGSYS, oldHandler);
1874202a189Smrg    return !badSysCall;
18805b261ecSmrg}
18905b261ecSmrg
19005b261ecSmrg#define MUST_CHECK_FOR_SHM_SYSCALL
19105b261ecSmrg
19205b261ecSmrg#endif
19305b261ecSmrg
1944202a189Smrgstatic Bool
195f7df2e56SmrgShmCloseScreen(ScreenPtr pScreen)
1964202a189Smrg{
1974202a189Smrg    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
198f7df2e56Smrg
1994202a189Smrg    pScreen->CloseScreen = screen_priv->CloseScreen;
2004202a189Smrg    dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL);
2014202a189Smrg    free(screen_priv);
202f7df2e56Smrg    return (*pScreen->CloseScreen) (pScreen);
2034202a189Smrg}
2044202a189Smrg
2054202a189Smrgstatic ShmScrPrivateRec *
2064202a189SmrgShmInitScreenPriv(ScreenPtr pScreen)
2074202a189Smrg{
2084202a189Smrg    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
209f7df2e56Smrg
210f7df2e56Smrg    if (!screen_priv) {
211f7df2e56Smrg        screen_priv = calloc(1, sizeof(ShmScrPrivateRec));
212f7df2e56Smrg        screen_priv->CloseScreen = pScreen->CloseScreen;
213f7df2e56Smrg        dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv);
214f7df2e56Smrg        pScreen->CloseScreen = ShmCloseScreen;
2154202a189Smrg    }
2164202a189Smrg    return screen_priv;
2174202a189Smrg}
2184202a189Smrg
2194202a189Smrgstatic Bool
2204202a189SmrgShmRegisterPrivates(void)
2214202a189Smrg{
2224202a189Smrg    if (!dixRegisterPrivateKey(&shmScrPrivateKeyRec, PRIVATE_SCREEN, 0))
223f7df2e56Smrg        return FALSE;
2244202a189Smrg    if (!dixRegisterPrivateKey(&shmPixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
225f7df2e56Smrg        return FALSE;
2264202a189Smrg    return TRUE;
2274202a189Smrg}
2284202a189Smrg
229f7df2e56Smrg /*ARGSUSED*/ static void
230f7df2e56SmrgShmResetProc(ExtensionEntry * extEntry)
23105b261ecSmrg{
23205b261ecSmrg    int i;
233f7df2e56Smrg
2344202a189Smrg    for (i = 0; i < screenInfo.numScreens; i++)
235f7df2e56Smrg        ShmRegisterFuncs(screenInfo.screens[i], NULL);
23605b261ecSmrg}
23705b261ecSmrg
2384202a189Smrgvoid
2394642e01fSmrgShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs)
24005b261ecSmrg{
2414202a189Smrg    if (!ShmRegisterPrivates())
242f7df2e56Smrg        return;
2434202a189Smrg    ShmInitScreenPriv(pScreen)->shmFuncs = funcs;
24405b261ecSmrg}
24505b261ecSmrg
24605b261ecSmrgstatic Bool
247f7df2e56SmrgShmDestroyPixmap(PixmapPtr pPixmap)
24805b261ecSmrg{
249f7df2e56Smrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
2504202a189Smrg    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
251f7df2e56Smrg    void *shmdesc = NULL;
252f7df2e56Smrg    Bool ret;
253f7df2e56Smrg
25405b261ecSmrg    if (pPixmap->refcnt == 1)
255f7df2e56Smrg        shmdesc = dixLookupPrivate(&pPixmap->devPrivates, shmPixmapPrivateKey);
256f7df2e56Smrg
2574202a189Smrg    pScreen->DestroyPixmap = screen_priv->destroyPixmap;
25805b261ecSmrg    ret = (*pScreen->DestroyPixmap) (pPixmap);
2594202a189Smrg    screen_priv->destroyPixmap = pScreen->DestroyPixmap;
26005b261ecSmrg    pScreen->DestroyPixmap = ShmDestroyPixmap;
261f7df2e56Smrg
262f7df2e56Smrg    if (shmdesc)
263f7df2e56Smrg	ShmDetachSegment(shmdesc, 0);
264f7df2e56Smrg
26505b261ecSmrg    return ret;
26605b261ecSmrg}
26705b261ecSmrg
2684202a189Smrgvoid
2694642e01fSmrgShmRegisterFbFuncs(ScreenPtr pScreen)
27005b261ecSmrg{
2714202a189Smrg    ShmRegisterFuncs(pScreen, &fbFuncs);
27205b261ecSmrg}
27305b261ecSmrg
27405b261ecSmrgstatic int
2754642e01fSmrgProcShmQueryVersion(ClientPtr client)
27605b261ecSmrg{
277f7df2e56Smrg    xShmQueryVersionReply rep = {
278f7df2e56Smrg        .type = X_Reply,
279f7df2e56Smrg        .sharedPixmaps = sharedPixmaps,
280f7df2e56Smrg        .sequenceNumber = client->sequence,
281f7df2e56Smrg        .length = 0,
282f7df2e56Smrg        .majorVersion = SERVER_SHM_MAJOR_VERSION,
283f7df2e56Smrg        .minorVersion = SERVER_SHM_MINOR_VERSION,
284f7df2e56Smrg        .uid = geteuid(),
285f7df2e56Smrg        .gid = getegid(),
286f7df2e56Smrg        .pixmapFormat = sharedPixmaps ? ZPixmap : 0
287f7df2e56Smrg    };
28805b261ecSmrg
28905b261ecSmrg    REQUEST_SIZE_MATCH(xShmQueryVersionReq);
290f7df2e56Smrg
29105b261ecSmrg    if (client->swapped) {
292f7df2e56Smrg        swaps(&rep.sequenceNumber);
293f7df2e56Smrg        swapl(&rep.length);
294f7df2e56Smrg        swaps(&rep.majorVersion);
295f7df2e56Smrg        swaps(&rep.minorVersion);
296f7df2e56Smrg        swaps(&rep.uid);
297f7df2e56Smrg        swaps(&rep.gid);
298f7df2e56Smrg    }
299f7df2e56Smrg    WriteToClient(client, sizeof(xShmQueryVersionReply), &rep);
3004202a189Smrg    return Success;
30105b261ecSmrg}
30205b261ecSmrg
30305b261ecSmrg/*
30405b261ecSmrg * Simulate the access() system call for a shared memory segement,
30505b261ecSmrg * using the credentials from the client if available
30605b261ecSmrg */
30705b261ecSmrgstatic int
308f7df2e56Smrgshm_access(ClientPtr client, SHMPERM_TYPE * perm, int readonly)
30905b261ecSmrg{
31005b261ecSmrg    int uid, gid;
31105b261ecSmrg    mode_t mask;
3124642e01fSmrg    int uidset = 0, gidset = 0;
3134642e01fSmrg    LocalClientCredRec *lcc;
314f7df2e56Smrg
3154642e01fSmrg    if (GetLocalClientCreds(client, &lcc) != -1) {
31605b261ecSmrg
317f7df2e56Smrg        if (lcc->fieldsSet & LCC_UID_SET) {
318f7df2e56Smrg            uid = lcc->euid;
319f7df2e56Smrg            uidset = 1;
320f7df2e56Smrg        }
321f7df2e56Smrg        if (lcc->fieldsSet & LCC_GID_SET) {
322f7df2e56Smrg            gid = lcc->egid;
323f7df2e56Smrg            gidset = 1;
324f7df2e56Smrg        }
3254642e01fSmrg
3264642e01fSmrg#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID)
327f7df2e56Smrg        if (((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1)
328f7df2e56Smrg            || (lcc->zoneid != SHMPERM_ZONEID(perm))) {
329f7df2e56Smrg            uidset = 0;
330f7df2e56Smrg            gidset = 0;
331f7df2e56Smrg        }
3324642e01fSmrg#endif
333f7df2e56Smrg        FreeLocalClientCreds(lcc);
334f7df2e56Smrg
335f7df2e56Smrg        if (uidset) {
336f7df2e56Smrg            /* User id 0 always gets access */
337f7df2e56Smrg            if (uid == 0) {
338f7df2e56Smrg                return 0;
339f7df2e56Smrg            }
340f7df2e56Smrg            /* Check the owner */
341f7df2e56Smrg            if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) {
342f7df2e56Smrg                mask = S_IRUSR;
343f7df2e56Smrg                if (!readonly) {
344f7df2e56Smrg                    mask |= S_IWUSR;
345f7df2e56Smrg                }
346f7df2e56Smrg                return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
347f7df2e56Smrg            }
348f7df2e56Smrg        }
349f7df2e56Smrg
350f7df2e56Smrg        if (gidset) {
351f7df2e56Smrg            /* Check the group */
352f7df2e56Smrg            if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) {
353f7df2e56Smrg                mask = S_IRGRP;
354f7df2e56Smrg                if (!readonly) {
355f7df2e56Smrg                    mask |= S_IWGRP;
356f7df2e56Smrg                }
357f7df2e56Smrg                return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
358f7df2e56Smrg            }
359f7df2e56Smrg        }
36005b261ecSmrg    }
36105b261ecSmrg    /* Otherwise, check everyone else */
36205b261ecSmrg    mask = S_IROTH;
36305b261ecSmrg    if (!readonly) {
364f7df2e56Smrg        mask |= S_IWOTH;
36505b261ecSmrg    }
3664642e01fSmrg    return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
36705b261ecSmrg}
36805b261ecSmrg
36905b261ecSmrgstatic int
3704642e01fSmrgProcShmAttach(ClientPtr client)
37105b261ecSmrg{
3724642e01fSmrg    SHMSTAT_TYPE buf;
37305b261ecSmrg    ShmDescPtr shmdesc;
374f7df2e56Smrg
37505b261ecSmrg    REQUEST(xShmAttachReq);
37605b261ecSmrg
37705b261ecSmrg    REQUEST_SIZE_MATCH(xShmAttachReq);
37805b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
379f7df2e56Smrg    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
380f7df2e56Smrg        client->errorValue = stuff->readOnly;
3814202a189Smrg        return BadValue;
38205b261ecSmrg    }
383f7df2e56Smrg    for (shmdesc = Shmsegs; shmdesc; shmdesc = shmdesc->next) {
384f7df2e56Smrg        if (!SHMDESC_IS_FD(shmdesc) && shmdesc->shmid == stuff->shmid)
385f7df2e56Smrg            break;
38605b261ecSmrg    }
387f7df2e56Smrg    if (shmdesc) {
388f7df2e56Smrg        if (!stuff->readOnly && !shmdesc->writable)
389f7df2e56Smrg            return BadAccess;
390f7df2e56Smrg        shmdesc->refcnt++;
391f7df2e56Smrg    }
392f7df2e56Smrg    else {
393f7df2e56Smrg        shmdesc = malloc(sizeof(ShmDescRec));
394f7df2e56Smrg        if (!shmdesc)
395f7df2e56Smrg            return BadAlloc;
396f7df2e56Smrg#ifdef SHM_FD_PASSING
397f7df2e56Smrg        shmdesc->is_fd = FALSE;
398f7df2e56Smrg#endif
399f7df2e56Smrg        shmdesc->addr = shmat(stuff->shmid, 0,
400f7df2e56Smrg                              stuff->readOnly ? SHM_RDONLY : 0);
401f7df2e56Smrg        if ((shmdesc->addr == ((char *) -1)) || SHMSTAT(stuff->shmid, &buf)) {
402f7df2e56Smrg            free(shmdesc);
403f7df2e56Smrg            return BadAccess;
404f7df2e56Smrg        }
405f7df2e56Smrg
406f7df2e56Smrg        /* The attach was performed with root privs. We must
407f7df2e56Smrg         * do manual checking of access rights for the credentials
408f7df2e56Smrg         * of the client */
409f7df2e56Smrg
410f7df2e56Smrg        if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) {
411f7df2e56Smrg            shmdt(shmdesc->addr);
412f7df2e56Smrg            free(shmdesc);
413f7df2e56Smrg            return BadAccess;
414f7df2e56Smrg        }
415f7df2e56Smrg
416f7df2e56Smrg        shmdesc->shmid = stuff->shmid;
417f7df2e56Smrg        shmdesc->refcnt = 1;
418f7df2e56Smrg        shmdesc->writable = !stuff->readOnly;
419f7df2e56Smrg        shmdesc->size = SHM_SEGSZ(buf);
420f7df2e56Smrg        shmdesc->next = Shmsegs;
421f7df2e56Smrg        Shmsegs = shmdesc;
42205b261ecSmrg    }
423f7df2e56Smrg    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
424f7df2e56Smrg        return BadAlloc;
4254202a189Smrg    return Success;
42605b261ecSmrg}
42705b261ecSmrg
428f7df2e56Smrg /*ARGSUSED*/ static int
429f7df2e56SmrgShmDetachSegment(void *value, /* must conform to DeleteType */
430f7df2e56Smrg                 XID unused)
43105b261ecSmrg{
432f7df2e56Smrg    ShmDescPtr shmdesc = (ShmDescPtr) value;
43305b261ecSmrg    ShmDescPtr *prev;
43405b261ecSmrg
43505b261ecSmrg    if (--shmdesc->refcnt)
436f7df2e56Smrg        return TRUE;
437f7df2e56Smrg#if SHM_FD_PASSING
438f7df2e56Smrg    if (shmdesc->is_fd) {
439f7df2e56Smrg        if (shmdesc->busfault)
440f7df2e56Smrg            busfault_unregister(shmdesc->busfault);
441f7df2e56Smrg        munmap(shmdesc->addr, shmdesc->size);
442f7df2e56Smrg    } else
443f7df2e56Smrg#endif
444f7df2e56Smrg        shmdt(shmdesc->addr);
445f7df2e56Smrg    for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next);
44605b261ecSmrg    *prev = shmdesc->next;
4474202a189Smrg    free(shmdesc);
44805b261ecSmrg    return Success;
44905b261ecSmrg}
45005b261ecSmrg
45105b261ecSmrgstatic int
4524642e01fSmrgProcShmDetach(ClientPtr client)
45305b261ecSmrg{
45405b261ecSmrg    ShmDescPtr shmdesc;
455f7df2e56Smrg
45605b261ecSmrg    REQUEST(xShmDetachReq);
45705b261ecSmrg
45805b261ecSmrg    REQUEST_SIZE_MATCH(xShmDetachReq);
45905b261ecSmrg    VERIFY_SHMSEG(stuff->shmseg, shmdesc, client);
46005b261ecSmrg    FreeResource(stuff->shmseg, RT_NONE);
4614202a189Smrg    return Success;
46205b261ecSmrg}
46305b261ecSmrg
4644642e01fSmrg/*
4654642e01fSmrg * If the given request doesn't exactly match PutImage's constraints,
4664642e01fSmrg * wrap the image in a scratch pixmap header and let CopyArea sort it out.
4674642e01fSmrg */
46805b261ecSmrgstatic void
4694642e01fSmrgdoShmPutImage(DrawablePtr dst, GCPtr pGC,
470f7df2e56Smrg              int depth, unsigned int format,
471f7df2e56Smrg              int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
472f7df2e56Smrg              char *data)
47305b261ecSmrg{
4744642e01fSmrg    PixmapPtr pPixmap;
4754202a189Smrg
47645bb0b75Smrg    if (format == ZPixmap || (format == XYPixmap && depth == 1)) {
477f7df2e56Smrg        pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth,
478f7df2e56Smrg                                         BitsPerPixel(depth),
479f7df2e56Smrg                                         PixmapBytePad(w, depth), data);
480f7df2e56Smrg        if (!pPixmap)
481f7df2e56Smrg            return;
482f7df2e56Smrg        pGC->ops->CopyArea((DrawablePtr) pPixmap, dst, pGC, sx, sy, sw, sh, dx,
483f7df2e56Smrg                           dy);
484f7df2e56Smrg        FreeScratchPixmapHeader(pPixmap);
485f7df2e56Smrg    }
486f7df2e56Smrg    else {
487f7df2e56Smrg        GCPtr putGC = GetScratchGC(depth, dst->pScreen);
488f7df2e56Smrg
489f7df2e56Smrg        if (!putGC)
490f7df2e56Smrg            return;
491f7df2e56Smrg
492f7df2e56Smrg        pPixmap = (*dst->pScreen->CreatePixmap) (dst->pScreen, sw, sh, depth,
493f7df2e56Smrg                                                 CREATE_PIXMAP_USAGE_SCRATCH);
494f7df2e56Smrg        if (!pPixmap) {
495f7df2e56Smrg            FreeScratchGC(putGC);
496f7df2e56Smrg            return;
497f7df2e56Smrg        }
498f7df2e56Smrg        ValidateGC(&pPixmap->drawable, putGC);
499f7df2e56Smrg        (*putGC->ops->PutImage) (&pPixmap->drawable, putGC, depth, -sx, -sy, w,
500f7df2e56Smrg                                 h, 0,
501f7df2e56Smrg                                 (format == XYPixmap) ? XYPixmap : ZPixmap,
502f7df2e56Smrg                                 data);
503f7df2e56Smrg        FreeScratchGC(putGC);
504f7df2e56Smrg        if (format == XYBitmap)
505f7df2e56Smrg            (void) (*pGC->ops->CopyPlane) (&pPixmap->drawable, dst, pGC, 0, 0,
506f7df2e56Smrg                                           sw, sh, dx, dy, 1L);
507f7df2e56Smrg        else
508f7df2e56Smrg            (void) (*pGC->ops->CopyArea) (&pPixmap->drawable, dst, pGC, 0, 0,
509f7df2e56Smrg                                          sw, sh, dx, dy);
510f7df2e56Smrg        (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap);
5114202a189Smrg    }
51205b261ecSmrg}
51305b261ecSmrg
51465b04b38Smrgstatic int
51565b04b38SmrgProcShmPutImage(ClientPtr client)
51605b261ecSmrg{
51765b04b38Smrg    GCPtr pGC;
51865b04b38Smrg    DrawablePtr pDraw;
51965b04b38Smrg    long length;
52065b04b38Smrg    ShmDescPtr shmdesc;
521f7df2e56Smrg
52205b261ecSmrg    REQUEST(xShmPutImageReq);
52365b04b38Smrg
52405b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
52565b04b38Smrg    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
52665b04b38Smrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client);
52765b04b38Smrg    if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse))
528f7df2e56Smrg        return BadValue;
529f7df2e56Smrg    if (stuff->format == XYBitmap) {
53065b04b38Smrg        if (stuff->depth != 1)
53165b04b38Smrg            return BadMatch;
53265b04b38Smrg        length = PixmapBytePad(stuff->totalWidth, 1);
53365b04b38Smrg    }
534f7df2e56Smrg    else if (stuff->format == XYPixmap) {
53565b04b38Smrg        if (pDraw->depth != stuff->depth)
53665b04b38Smrg            return BadMatch;
53765b04b38Smrg        length = PixmapBytePad(stuff->totalWidth, 1);
538f7df2e56Smrg        length *= stuff->depth;
53965b04b38Smrg    }
540f7df2e56Smrg    else if (stuff->format == ZPixmap) {
54165b04b38Smrg        if (pDraw->depth != stuff->depth)
54265b04b38Smrg            return BadMatch;
54365b04b38Smrg        length = PixmapBytePad(stuff->totalWidth, stuff->depth);
54465b04b38Smrg    }
545f7df2e56Smrg    else {
546f7df2e56Smrg        client->errorValue = stuff->format;
54765b04b38Smrg        return BadValue;
54865b04b38Smrg    }
54905b261ecSmrg
55065b04b38Smrg    /*
55165b04b38Smrg     * There's a potential integer overflow in this check:
55265b04b38Smrg     * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight,
55365b04b38Smrg     *                client);
55465b04b38Smrg     * the version below ought to avoid it
55565b04b38Smrg     */
55665b04b38Smrg    if (stuff->totalHeight != 0 &&
557f7df2e56Smrg        length > (shmdesc->size - stuff->offset) / stuff->totalHeight) {
558f7df2e56Smrg        client->errorValue = stuff->totalWidth;
559f7df2e56Smrg        return BadValue;
56065b04b38Smrg    }
561f7df2e56Smrg    if (stuff->srcX > stuff->totalWidth) {
562f7df2e56Smrg        client->errorValue = stuff->srcX;
563f7df2e56Smrg        return BadValue;
56465b04b38Smrg    }
565f7df2e56Smrg    if (stuff->srcY > stuff->totalHeight) {
566f7df2e56Smrg        client->errorValue = stuff->srcY;
567f7df2e56Smrg        return BadValue;
56865b04b38Smrg    }
569f7df2e56Smrg    if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) {
570f7df2e56Smrg        client->errorValue = stuff->srcWidth;
571f7df2e56Smrg        return BadValue;
57265b04b38Smrg    }
573f7df2e56Smrg    if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) {
574f7df2e56Smrg        client->errorValue = stuff->srcHeight;
575f7df2e56Smrg        return BadValue;
57665b04b38Smrg    }
57705b261ecSmrg
57865b04b38Smrg    if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) ||
579f7df2e56Smrg         ((stuff->format != ZPixmap) &&
580f7df2e56Smrg          (stuff->srcX < screenInfo.bitmapScanlinePad) &&
581f7df2e56Smrg          ((stuff->format == XYBitmap) ||
582f7df2e56Smrg           ((stuff->srcY == 0) &&
583f7df2e56Smrg            (stuff->srcHeight == stuff->totalHeight))))) &&
584f7df2e56Smrg        ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth))
585f7df2e56Smrg        (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth,
586f7df2e56Smrg                               stuff->dstX, stuff->dstY,
587f7df2e56Smrg                               stuff->totalWidth, stuff->srcHeight,
588f7df2e56Smrg                               stuff->srcX, stuff->format,
589f7df2e56Smrg                               shmdesc->addr + stuff->offset +
590f7df2e56Smrg                               (stuff->srcY * length));
59165b04b38Smrg    else
592f7df2e56Smrg        doShmPutImage(pDraw, pGC, stuff->depth, stuff->format,
593f7df2e56Smrg                      stuff->totalWidth, stuff->totalHeight,
594f7df2e56Smrg                      stuff->srcX, stuff->srcY,
595f7df2e56Smrg                      stuff->srcWidth, stuff->srcHeight,
596f7df2e56Smrg                      stuff->dstX, stuff->dstY, shmdesc->addr + stuff->offset);
597f7df2e56Smrg
598f7df2e56Smrg    if (stuff->sendEvent) {
599f7df2e56Smrg        xShmCompletionEvent ev = {
600f7df2e56Smrg            .type = ShmCompletionCode,
601f7df2e56Smrg            .drawable = stuff->drawable,
602f7df2e56Smrg            .minorEvent = X_ShmPutImage,
603f7df2e56Smrg            .majorEvent = ShmReqCode,
604f7df2e56Smrg            .shmseg = stuff->shmseg,
605f7df2e56Smrg            .offset = stuff->offset
606f7df2e56Smrg        };
607f7df2e56Smrg        WriteEventsToClient(client, 1, (xEvent *) &ev);
60805b261ecSmrg    }
60965b04b38Smrg
61065b04b38Smrg    return Success;
61105b261ecSmrg}
61205b261ecSmrg
61365b04b38Smrgstatic int
61465b04b38SmrgProcShmGetImage(ClientPtr client)
61505b261ecSmrg{
616f7df2e56Smrg    DrawablePtr pDraw;
617f7df2e56Smrg    long lenPer = 0, length;
618f7df2e56Smrg    Mask plane = 0;
619f7df2e56Smrg    xShmGetImageReply xgi;
620f7df2e56Smrg    ShmDescPtr shmdesc;
621f7df2e56Smrg    VisualID visual = None;
622f7df2e56Smrg    RegionPtr pVisibleRegion = NULL;
623f7df2e56Smrg    int rc;
62405b261ecSmrg
62505b261ecSmrg    REQUEST(xShmGetImageReq);
62605b261ecSmrg
62705b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
628f7df2e56Smrg    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
629f7df2e56Smrg        client->errorValue = stuff->format;
6304202a189Smrg        return BadValue;
63105b261ecSmrg    }
632f7df2e56Smrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
63305b261ecSmrg    if (rc != Success)
634f7df2e56Smrg        return rc;
63505b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
636f7df2e56Smrg    if (pDraw->type == DRAWABLE_WINDOW) {
637f7df2e56Smrg        if (   /* check for being viewable */
638f7df2e56Smrg               !((WindowPtr) pDraw)->realized ||
639f7df2e56Smrg               /* check for being on screen */
640f7df2e56Smrg               pDraw->x + stuff->x < 0 ||
641f7df2e56Smrg               pDraw->x + stuff->x + (int) stuff->width > pDraw->pScreen->width
642f7df2e56Smrg               || pDraw->y + stuff->y < 0 ||
643f7df2e56Smrg               pDraw->y + stuff->y + (int) stuff->height >
644f7df2e56Smrg               pDraw->pScreen->height ||
645f7df2e56Smrg               /* check for being inside of border */
646f7df2e56Smrg               stuff->x < -wBorderWidth((WindowPtr) pDraw) ||
647f7df2e56Smrg               stuff->x + (int) stuff->width >
648f7df2e56Smrg               wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
649f7df2e56Smrg               stuff->y < -wBorderWidth((WindowPtr) pDraw) ||
650f7df2e56Smrg               stuff->y + (int) stuff->height >
651f7df2e56Smrg               wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
652f7df2e56Smrg            return BadMatch;
653f7df2e56Smrg        visual = wVisual(((WindowPtr) pDraw));
654f7df2e56Smrg        pVisibleRegion = NotClippedByChildren((WindowPtr) pDraw);
655f7df2e56Smrg        if (pVisibleRegion)
656f7df2e56Smrg            RegionTranslate(pVisibleRegion, -pDraw->x, -pDraw->y);
65765b04b38Smrg    }
658f7df2e56Smrg    else {
659f7df2e56Smrg        if (stuff->x < 0 ||
660f7df2e56Smrg            stuff->x + (int) stuff->width > pDraw->width ||
661f7df2e56Smrg            stuff->y < 0 || stuff->y + (int) stuff->height > pDraw->height)
662f7df2e56Smrg            return BadMatch;
663f7df2e56Smrg        visual = None;
66465b04b38Smrg    }
665f7df2e56Smrg    xgi = (xShmGetImageReply) {
666f7df2e56Smrg        .type = X_Reply,
667f7df2e56Smrg        .sequenceNumber = client->sequence,
668f7df2e56Smrg        .length = 0,
669f7df2e56Smrg        .visual = visual,
670f7df2e56Smrg        .depth = pDraw->depth
671f7df2e56Smrg    };
672f7df2e56Smrg    if (stuff->format == ZPixmap) {
673f7df2e56Smrg        length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height;
674f7df2e56Smrg    }
675f7df2e56Smrg    else {
676f7df2e56Smrg        lenPer = PixmapBytePad(stuff->width, 1) * stuff->height;
677f7df2e56Smrg        plane = ((Mask) 1) << (pDraw->depth - 1);
678f7df2e56Smrg        /* only planes asked for */
679f7df2e56Smrg        length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
68065b04b38Smrg    }
68165b04b38Smrg
68265b04b38Smrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
68365b04b38Smrg    xgi.size = length;
68465b04b38Smrg
685f7df2e56Smrg    if (length == 0) {
686f7df2e56Smrg        /* nothing to do */
68765b04b38Smrg    }
688f7df2e56Smrg    else if (stuff->format == ZPixmap) {
689f7df2e56Smrg        (*pDraw->pScreen->GetImage) (pDraw, stuff->x, stuff->y,
690f7df2e56Smrg                                     stuff->width, stuff->height,
691f7df2e56Smrg                                     stuff->format, stuff->planeMask,
692f7df2e56Smrg                                     shmdesc->addr + stuff->offset);
693f7df2e56Smrg        if (pVisibleRegion)
694f7df2e56Smrg            XaceCensorImage(client, pVisibleRegion,
695f7df2e56Smrg                    PixmapBytePad(stuff->width, pDraw->depth), pDraw,
696f7df2e56Smrg                    stuff->x, stuff->y, stuff->width, stuff->height,
697f7df2e56Smrg                    stuff->format, shmdesc->addr + stuff->offset);
69865b04b38Smrg    }
699f7df2e56Smrg    else {
70065b04b38Smrg
701f7df2e56Smrg        length = stuff->offset;
702f7df2e56Smrg        for (; plane; plane >>= 1) {
703f7df2e56Smrg            if (stuff->planeMask & plane) {
704f7df2e56Smrg                (*pDraw->pScreen->GetImage) (pDraw,
705f7df2e56Smrg                                             stuff->x, stuff->y,
706f7df2e56Smrg                                             stuff->width, stuff->height,
707f7df2e56Smrg                                             stuff->format, plane,
708f7df2e56Smrg                                             shmdesc->addr + length);
709f7df2e56Smrg                if (pVisibleRegion)
710f7df2e56Smrg                    XaceCensorImage(client, pVisibleRegion,
711f7df2e56Smrg                            BitmapBytePad(stuff->width), pDraw,
712f7df2e56Smrg                            stuff->x, stuff->y, stuff->width, stuff->height,
713f7df2e56Smrg                            stuff->format, shmdesc->addr + length);
714f7df2e56Smrg                length += lenPer;
715f7df2e56Smrg            }
716f7df2e56Smrg        }
71765b04b38Smrg    }
71865b04b38Smrg
719f7df2e56Smrg    if (pVisibleRegion)
720f7df2e56Smrg        RegionDestroy(pVisibleRegion);
721f7df2e56Smrg
72265b04b38Smrg    if (client->swapped) {
723f7df2e56Smrg        swaps(&xgi.sequenceNumber);
724f7df2e56Smrg        swapl(&xgi.length);
725f7df2e56Smrg        swapl(&xgi.visual);
726f7df2e56Smrg        swapl(&xgi.size);
72765b04b38Smrg    }
728f7df2e56Smrg    WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
72965b04b38Smrg
73065b04b38Smrg    return Success;
73165b04b38Smrg}
73265b04b38Smrg
73365b04b38Smrg#ifdef PANORAMIX
734f7df2e56Smrgstatic int
73565b04b38SmrgProcPanoramiXShmPutImage(ClientPtr client)
73665b04b38Smrg{
737f7df2e56Smrg    int j, result, orig_x, orig_y;
738f7df2e56Smrg    PanoramiXRes *draw, *gc;
739f7df2e56Smrg    Bool sendEvent, isRoot;
74065b04b38Smrg
74165b04b38Smrg    REQUEST(xShmPutImageReq);
74265b04b38Smrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
74365b04b38Smrg
744f7df2e56Smrg    result = dixLookupResourceByClass((void **) &draw, stuff->drawable,
745f7df2e56Smrg                                      XRC_DRAWABLE, client, DixWriteAccess);
74665b04b38Smrg    if (result != Success)
74765b04b38Smrg        return (result == BadValue) ? BadDrawable : result;
74865b04b38Smrg
749f7df2e56Smrg    result = dixLookupResourceByType((void **) &gc, stuff->gc,
750f7df2e56Smrg                                     XRT_GC, client, DixReadAccess);
75165b04b38Smrg    if (result != Success)
75265b04b38Smrg        return result;
75365b04b38Smrg
75465b04b38Smrg    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
75565b04b38Smrg
75665b04b38Smrg    orig_x = stuff->dstX;
75765b04b38Smrg    orig_y = stuff->dstY;
75865b04b38Smrg    sendEvent = stuff->sendEvent;
75965b04b38Smrg    stuff->sendEvent = 0;
76065b04b38Smrg    FOR_NSCREENS(j) {
761f7df2e56Smrg        if (!j)
762f7df2e56Smrg            stuff->sendEvent = sendEvent;
763f7df2e56Smrg        stuff->drawable = draw->info[j].id;
764f7df2e56Smrg        stuff->gc = gc->info[j].id;
765f7df2e56Smrg        if (isRoot) {
766f7df2e56Smrg            stuff->dstX = orig_x - screenInfo.screens[j]->x;
767f7df2e56Smrg            stuff->dstY = orig_y - screenInfo.screens[j]->y;
768f7df2e56Smrg        }
769f7df2e56Smrg        result = ProcShmPutImage(client);
770f7df2e56Smrg        if (result != Success)
771f7df2e56Smrg            break;
77265b04b38Smrg    }
77365b04b38Smrg    return result;
77465b04b38Smrg}
77565b04b38Smrg
776f7df2e56Smrgstatic int
77765b04b38SmrgProcPanoramiXShmGetImage(ClientPtr client)
77865b04b38Smrg{
779f7df2e56Smrg    PanoramiXRes *draw;
780f7df2e56Smrg    DrawablePtr *drawables;
781f7df2e56Smrg    DrawablePtr pDraw;
782f7df2e56Smrg    xShmGetImageReply xgi;
783f7df2e56Smrg    ShmDescPtr shmdesc;
784f7df2e56Smrg    int i, x, y, w, h, format, rc;
785f7df2e56Smrg    Mask plane = 0, planemask;
786f7df2e56Smrg    long lenPer = 0, length, widthBytesLine;
787f7df2e56Smrg    Bool isRoot;
78865b04b38Smrg
78965b04b38Smrg    REQUEST(xShmGetImageReq);
79065b04b38Smrg
79165b04b38Smrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
79265b04b38Smrg
79365b04b38Smrg    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
794f7df2e56Smrg        client->errorValue = stuff->format;
79565b04b38Smrg        return BadValue;
79665b04b38Smrg    }
79765b04b38Smrg
798f7df2e56Smrg    rc = dixLookupResourceByClass((void **) &draw, stuff->drawable,
799f7df2e56Smrg                                  XRC_DRAWABLE, client, DixWriteAccess);
80065b04b38Smrg    if (rc != Success)
801f7df2e56Smrg        return (rc == BadValue) ? BadDrawable : rc;
80265b04b38Smrg
80365b04b38Smrg    if (draw->type == XRT_PIXMAP)
804f7df2e56Smrg        return ProcShmGetImage(client);
80565b04b38Smrg
806f7df2e56Smrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
80765b04b38Smrg    if (rc != Success)
808f7df2e56Smrg        return rc;
80965b04b38Smrg
81065b04b38Smrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
81165b04b38Smrg
81265b04b38Smrg    x = stuff->x;
81365b04b38Smrg    y = stuff->y;
81465b04b38Smrg    w = stuff->width;
81565b04b38Smrg    h = stuff->height;
81665b04b38Smrg    format = stuff->format;
81765b04b38Smrg    planemask = stuff->planeMask;
81865b04b38Smrg
81965b04b38Smrg    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
82065b04b38Smrg
821f7df2e56Smrg    if (isRoot) {
822f7df2e56Smrg        if (                    /* check for being onscreen */
823f7df2e56Smrg               x < 0 || x + w > PanoramiXPixWidth ||
824f7df2e56Smrg               y < 0 || y + h > PanoramiXPixHeight)
825f7df2e56Smrg            return BadMatch;
826f7df2e56Smrg    }
827f7df2e56Smrg    else {
828f7df2e56Smrg        if (                    /* check for being onscreen */
829f7df2e56Smrg               screenInfo.screens[0]->x + pDraw->x + x < 0 ||
830f7df2e56Smrg               screenInfo.screens[0]->x + pDraw->x + x + w > PanoramiXPixWidth
831f7df2e56Smrg               || screenInfo.screens[0]->y + pDraw->y + y < 0 ||
832f7df2e56Smrg               screenInfo.screens[0]->y + pDraw->y + y + h > PanoramiXPixHeight
833f7df2e56Smrg               ||
834f7df2e56Smrg               /* check for being inside of border */
835f7df2e56Smrg               x < -wBorderWidth((WindowPtr) pDraw) ||
836f7df2e56Smrg               x + w > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
837f7df2e56Smrg               y < -wBorderWidth((WindowPtr) pDraw) ||
838f7df2e56Smrg               y + h > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
839f7df2e56Smrg            return BadMatch;
84065b04b38Smrg    }
84165b04b38Smrg
8424202a189Smrg    drawables = calloc(PanoramiXNumScreens, sizeof(DrawablePtr));
843f7df2e56Smrg    if (!drawables)
844f7df2e56Smrg        return BadAlloc;
8454202a189Smrg
84605b261ecSmrg    drawables[0] = pDraw;
847f7df2e56Smrg    FOR_NSCREENS_FORWARD_SKIP(i) {
848f7df2e56Smrg        rc = dixLookupDrawable(drawables + i, draw->info[i].id, client, 0,
849f7df2e56Smrg                               DixReadAccess);
850f7df2e56Smrg        if (rc != Success) {
851f7df2e56Smrg            free(drawables);
852f7df2e56Smrg            return rc;
853f7df2e56Smrg        }
85405b261ecSmrg    }
85505b261ecSmrg
856f7df2e56Smrg    xgi = (xShmGetImageReply) {
857f7df2e56Smrg        .type = X_Reply,
858f7df2e56Smrg        .sequenceNumber = client->sequence,
859f7df2e56Smrg        .length = 0,
860f7df2e56Smrg        .visual = wVisual(((WindowPtr) pDraw)),
861f7df2e56Smrg        .depth = pDraw->depth
862f7df2e56Smrg    };
863f7df2e56Smrg
864f7df2e56Smrg    if (format == ZPixmap) {
865f7df2e56Smrg        widthBytesLine = PixmapBytePad(w, pDraw->depth);
866f7df2e56Smrg        length = widthBytesLine * h;
867f7df2e56Smrg    }
868f7df2e56Smrg    else {
869f7df2e56Smrg        widthBytesLine = PixmapBytePad(w, 1);
870f7df2e56Smrg        lenPer = widthBytesLine * h;
871f7df2e56Smrg        plane = ((Mask) 1) << (pDraw->depth - 1);
872f7df2e56Smrg        length = lenPer * Ones(planemask & (plane | (plane - 1)));
87305b261ecSmrg    }
87405b261ecSmrg
87505b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
87605b261ecSmrg    xgi.size = length;
87705b261ecSmrg
878f7df2e56Smrg    if (length == 0) {          /* nothing to do */
879f7df2e56Smrg    }
88005b261ecSmrg    else if (format == ZPixmap) {
881f7df2e56Smrg        XineramaGetImageData(drawables, x, y, w, h, format, planemask,
882f7df2e56Smrg                             shmdesc->addr + stuff->offset,
883f7df2e56Smrg                             widthBytesLine, isRoot);
884f7df2e56Smrg    }
885f7df2e56Smrg    else {
88605b261ecSmrg
887f7df2e56Smrg        length = stuff->offset;
88805b261ecSmrg        for (; plane; plane >>= 1) {
889f7df2e56Smrg            if (planemask & plane) {
890f7df2e56Smrg                XineramaGetImageData(drawables, x, y, w, h,
891f7df2e56Smrg                                     format, plane, shmdesc->addr + length,
892f7df2e56Smrg                                     widthBytesLine, isRoot);
893f7df2e56Smrg                length += lenPer;
894f7df2e56Smrg            }
895f7df2e56Smrg        }
89605b261ecSmrg    }
8974202a189Smrg    free(drawables);
898f7df2e56Smrg
89905b261ecSmrg    if (client->swapped) {
900f7df2e56Smrg        swaps(&xgi.sequenceNumber);
901f7df2e56Smrg        swapl(&xgi.length);
902f7df2e56Smrg        swapl(&xgi.visual);
903f7df2e56Smrg        swapl(&xgi.size);
90405b261ecSmrg    }
905f7df2e56Smrg    WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
90605b261ecSmrg
9074202a189Smrg    return Success;
90805b261ecSmrg}
90905b261ecSmrg
91005b261ecSmrgstatic int
9114642e01fSmrgProcPanoramiXShmCreatePixmap(ClientPtr client)
91205b261ecSmrg{
91305b261ecSmrg    ScreenPtr pScreen = NULL;
91405b261ecSmrg    PixmapPtr pMap = NULL;
91505b261ecSmrg    DrawablePtr pDraw;
91605b261ecSmrg    DepthPtr pDepth;
91705b261ecSmrg    int i, j, result, rc;
91805b261ecSmrg    ShmDescPtr shmdesc;
919f7df2e56Smrg
92005b261ecSmrg    REQUEST(xShmCreatePixmapReq);
92105b261ecSmrg    unsigned int width, height, depth;
92205b261ecSmrg    unsigned long size;
92305b261ecSmrg    PanoramiXRes *newPix;
92405b261ecSmrg
92505b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
92605b261ecSmrg    client->errorValue = stuff->pid;
92705b261ecSmrg    if (!sharedPixmaps)
928f7df2e56Smrg        return BadImplementation;
92905b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->pid, client);
93005b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
931f7df2e56Smrg                           DixGetAttrAccess);
93205b261ecSmrg    if (rc != Success)
933f7df2e56Smrg        return rc;
93405b261ecSmrg
93505b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
93605b261ecSmrg
93705b261ecSmrg    width = stuff->width;
93805b261ecSmrg    height = stuff->height;
93905b261ecSmrg    depth = stuff->depth;
940f7df2e56Smrg    if (!width || !height || !depth) {
941f7df2e56Smrg        client->errorValue = 0;
94205b261ecSmrg        return BadValue;
94305b261ecSmrg    }
94405b261ecSmrg    if (width > 32767 || height > 32767)
94505b261ecSmrg        return BadAlloc;
94605b261ecSmrg
947f7df2e56Smrg    if (stuff->depth != 1) {
94805b261ecSmrg        pDepth = pDraw->pScreen->allowedDepths;
949f7df2e56Smrg        for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
950f7df2e56Smrg            if (pDepth->depth == stuff->depth)
951f7df2e56Smrg                goto CreatePmap;
952f7df2e56Smrg        client->errorValue = stuff->depth;
95305b261ecSmrg        return BadValue;
95405b261ecSmrg    }
95505b261ecSmrg
956f7df2e56Smrg CreatePmap:
95705b261ecSmrg    size = PixmapBytePad(width, depth) * height;
95805b261ecSmrg    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
95905b261ecSmrg        if (size < width * height)
96005b261ecSmrg            return BadAlloc;
96105b261ecSmrg    }
96205b261ecSmrg    /* thankfully, offset is unsigned */
96305b261ecSmrg    if (stuff->offset + size < size)
964f7df2e56Smrg        return BadAlloc;
96505b261ecSmrg
96605b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
96705b261ecSmrg
968f7df2e56Smrg    if (!(newPix = malloc(sizeof(PanoramiXRes))))
969f7df2e56Smrg        return BadAlloc;
97005b261ecSmrg
97105b261ecSmrg    newPix->type = XRT_PIXMAP;
97205b261ecSmrg    newPix->u.pix.shared = TRUE;
973f7df2e56Smrg    panoramix_setup_ids(newPix, client, stuff->pid);
97405b261ecSmrg
9754202a189Smrg    result = Success;
97605b261ecSmrg
97705b261ecSmrg    FOR_NSCREENS(j) {
978f7df2e56Smrg        ShmScrPrivateRec *screen_priv;
979f7df2e56Smrg
980f7df2e56Smrg        pScreen = screenInfo.screens[j];
981f7df2e56Smrg
982f7df2e56Smrg        screen_priv = ShmGetScreenPriv(pScreen);
983f7df2e56Smrg        pMap = (*screen_priv->shmFuncs->CreatePixmap) (pScreen,
984f7df2e56Smrg                                                       stuff->width,
985f7df2e56Smrg                                                       stuff->height,
986f7df2e56Smrg                                                       stuff->depth,
987f7df2e56Smrg                                                       shmdesc->addr +
988f7df2e56Smrg                                                       stuff->offset);
989f7df2e56Smrg
990f7df2e56Smrg        if (pMap) {
991f7df2e56Smrg            result = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid,
992f7df2e56Smrg                              RT_PIXMAP, pMap, RT_NONE, NULL, DixCreateAccess);
993f7df2e56Smrg            if (result != Success) {
994f7df2e56Smrg                pDraw->pScreen->DestroyPixmap(pMap);
995f7df2e56Smrg                return result;
996f7df2e56Smrg            }
997f7df2e56Smrg            dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
99805b261ecSmrg            shmdesc->refcnt++;
999f7df2e56Smrg            pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1000f7df2e56Smrg            pMap->drawable.id = newPix->info[j].id;
1001f7df2e56Smrg            if (!AddResource(newPix->info[j].id, RT_PIXMAP, (void *) pMap)) {
1002f7df2e56Smrg                result = BadAlloc;
1003f7df2e56Smrg                break;
1004f7df2e56Smrg            }
1005f7df2e56Smrg        }
1006f7df2e56Smrg        else {
1007f7df2e56Smrg            result = BadAlloc;
1008f7df2e56Smrg            break;
1009f7df2e56Smrg        }
101005b261ecSmrg    }
101105b261ecSmrg
1012f7df2e56Smrg    if (result == BadAlloc) {
1013f7df2e56Smrg        while (j--)
1014f7df2e56Smrg            FreeResource(newPix->info[j].id, RT_NONE);
1015f7df2e56Smrg        free(newPix);
1016f7df2e56Smrg    }
1017f7df2e56Smrg    else
1018f7df2e56Smrg        AddResource(stuff->pid, XRT_PIXMAP, newPix);
101905b261ecSmrg
102005b261ecSmrg    return result;
102105b261ecSmrg}
102205b261ecSmrg#endif
102305b261ecSmrg
102405b261ecSmrgstatic PixmapPtr
1025f7df2e56SmrgfbShmCreatePixmap(ScreenPtr pScreen,
1026f7df2e56Smrg                  int width, int height, int depth, char *addr)
102705b261ecSmrg{
10284642e01fSmrg    PixmapPtr pPixmap;
102905b261ecSmrg
1030f7df2e56Smrg    pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0);
103105b261ecSmrg    if (!pPixmap)
1032f7df2e56Smrg        return NullPixmap;
1033f7df2e56Smrg
1034f7df2e56Smrg    if (!(*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth,
1035f7df2e56Smrg                                         BitsPerPixel(depth),
1036f7df2e56Smrg                                         PixmapBytePad(width, depth),
1037f7df2e56Smrg                                         (void *) addr)) {
1038f7df2e56Smrg        (*pScreen->DestroyPixmap) (pPixmap);
1039f7df2e56Smrg        return NullPixmap;
104005b261ecSmrg    }
104105b261ecSmrg    return pPixmap;
104205b261ecSmrg}
104305b261ecSmrg
104405b261ecSmrgstatic int
10454642e01fSmrgProcShmCreatePixmap(ClientPtr client)
104605b261ecSmrg{
104705b261ecSmrg    PixmapPtr pMap;
104805b261ecSmrg    DrawablePtr pDraw;
104905b261ecSmrg    DepthPtr pDepth;
10504642e01fSmrg    int i, rc;
105105b261ecSmrg    ShmDescPtr shmdesc;
10524202a189Smrg    ShmScrPrivateRec *screen_priv;
1053f7df2e56Smrg
105405b261ecSmrg    REQUEST(xShmCreatePixmapReq);
105505b261ecSmrg    unsigned int width, height, depth;
105605b261ecSmrg    unsigned long size;
105705b261ecSmrg
105805b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
105905b261ecSmrg    client->errorValue = stuff->pid;
106005b261ecSmrg    if (!sharedPixmaps)
1061f7df2e56Smrg        return BadImplementation;
106205b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->pid, client);
106305b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
1064f7df2e56Smrg                           DixGetAttrAccess);
106505b261ecSmrg    if (rc != Success)
1066f7df2e56Smrg        return rc;
106705b261ecSmrg
106805b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
1069f7df2e56Smrg
107005b261ecSmrg    width = stuff->width;
107105b261ecSmrg    height = stuff->height;
107205b261ecSmrg    depth = stuff->depth;
1073f7df2e56Smrg    if (!width || !height || !depth) {
1074f7df2e56Smrg        client->errorValue = 0;
107505b261ecSmrg        return BadValue;
107605b261ecSmrg    }
107705b261ecSmrg    if (width > 32767 || height > 32767)
1078f7df2e56Smrg        return BadAlloc;
107905b261ecSmrg
1080f7df2e56Smrg    if (stuff->depth != 1) {
108105b261ecSmrg        pDepth = pDraw->pScreen->allowedDepths;
1082f7df2e56Smrg        for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
1083f7df2e56Smrg            if (pDepth->depth == stuff->depth)
1084f7df2e56Smrg                goto CreatePmap;
1085f7df2e56Smrg        client->errorValue = stuff->depth;
108605b261ecSmrg        return BadValue;
108705b261ecSmrg    }
108805b261ecSmrg
1089f7df2e56Smrg CreatePmap:
109005b261ecSmrg    size = PixmapBytePad(width, depth) * height;
109105b261ecSmrg    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
1092f7df2e56Smrg        if (size < width * height)
1093f7df2e56Smrg            return BadAlloc;
109405b261ecSmrg    }
109505b261ecSmrg    /* thankfully, offset is unsigned */
109605b261ecSmrg    if (stuff->offset + size < size)
1097f7df2e56Smrg        return BadAlloc;
109805b261ecSmrg
109905b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
11004202a189Smrg    screen_priv = ShmGetScreenPriv(pDraw->pScreen);
1101f7df2e56Smrg    pMap = (*screen_priv->shmFuncs->CreatePixmap) (pDraw->pScreen, stuff->width,
1102f7df2e56Smrg                                                   stuff->height, stuff->depth,
1103f7df2e56Smrg                                                   shmdesc->addr +
1104f7df2e56Smrg                                                   stuff->offset);
1105f7df2e56Smrg    if (pMap) {
1106f7df2e56Smrg        rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP,
1107f7df2e56Smrg                      pMap, RT_NONE, NULL, DixCreateAccess);
1108f7df2e56Smrg        if (rc != Success) {
1109f7df2e56Smrg            pDraw->pScreen->DestroyPixmap(pMap);
1110f7df2e56Smrg            return rc;
1111f7df2e56Smrg        }
1112f7df2e56Smrg        dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
1113f7df2e56Smrg        shmdesc->refcnt++;
1114f7df2e56Smrg        pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1115f7df2e56Smrg        pMap->drawable.id = stuff->pid;
1116f7df2e56Smrg        if (AddResource(stuff->pid, RT_PIXMAP, (void *) pMap)) {
1117f7df2e56Smrg            return Success;
1118f7df2e56Smrg        }
1119f7df2e56Smrg    }
1120f7df2e56Smrg    return BadAlloc;
1121f7df2e56Smrg}
1122f7df2e56Smrg
1123f7df2e56Smrg#ifdef SHM_FD_PASSING
1124f7df2e56Smrg
1125f7df2e56Smrgstatic void
1126f7df2e56SmrgShmBusfaultNotify(void *context)
1127f7df2e56Smrg{
1128f7df2e56Smrg    ShmDescPtr shmdesc = context;
1129f7df2e56Smrg
1130f7df2e56Smrg    ErrorF("shared memory 0x%x truncated by client\n",
1131f7df2e56Smrg           (unsigned int) shmdesc->resource);
1132f7df2e56Smrg    busfault_unregister(shmdesc->busfault);
1133f7df2e56Smrg    shmdesc->busfault = NULL;
1134f7df2e56Smrg    FreeResource (shmdesc->resource, RT_NONE);
1135f7df2e56Smrg}
1136f7df2e56Smrg
1137f7df2e56Smrgstatic int
1138f7df2e56SmrgProcShmAttachFd(ClientPtr client)
1139f7df2e56Smrg{
1140f7df2e56Smrg    int fd;
1141f7df2e56Smrg    ShmDescPtr shmdesc;
1142f7df2e56Smrg    REQUEST(xShmAttachFdReq);
1143f7df2e56Smrg    struct stat statb;
1144f7df2e56Smrg
1145f7df2e56Smrg    SetReqFds(client, 1);
1146f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmAttachFdReq);
1147f7df2e56Smrg    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
1148f7df2e56Smrg    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1149f7df2e56Smrg        client->errorValue = stuff->readOnly;
1150f7df2e56Smrg        return BadValue;
1151f7df2e56Smrg    }
1152f7df2e56Smrg    fd = ReadFdFromClient(client);
1153f7df2e56Smrg    if (fd < 0)
1154f7df2e56Smrg        return BadMatch;
1155f7df2e56Smrg
1156f7df2e56Smrg    if (fstat(fd, &statb) < 0 || statb.st_size == 0) {
1157f7df2e56Smrg        close(fd);
1158f7df2e56Smrg        return BadMatch;
1159f7df2e56Smrg    }
1160f7df2e56Smrg
1161f7df2e56Smrg    shmdesc = malloc(sizeof(ShmDescRec));
1162f7df2e56Smrg    if (!shmdesc) {
1163f7df2e56Smrg        close(fd);
1164f7df2e56Smrg        return BadAlloc;
1165f7df2e56Smrg    }
1166f7df2e56Smrg    shmdesc->is_fd = TRUE;
1167f7df2e56Smrg    shmdesc->addr = mmap(NULL, statb.st_size,
1168f7df2e56Smrg                         stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1169f7df2e56Smrg                         MAP_SHARED,
1170f7df2e56Smrg                         fd, 0);
1171f7df2e56Smrg
1172f7df2e56Smrg    close(fd);
1173f7df2e56Smrg    if (shmdesc->addr == ((char *) -1)) {
1174f7df2e56Smrg        free(shmdesc);
1175f7df2e56Smrg        return BadAccess;
1176f7df2e56Smrg    }
1177f7df2e56Smrg
1178f7df2e56Smrg    shmdesc->refcnt = 1;
1179f7df2e56Smrg    shmdesc->writable = !stuff->readOnly;
1180f7df2e56Smrg    shmdesc->size = statb.st_size;
1181f7df2e56Smrg    shmdesc->resource = stuff->shmseg;
1182f7df2e56Smrg
1183f7df2e56Smrg    shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1184f7df2e56Smrg    if (!shmdesc->busfault) {
1185f7df2e56Smrg        munmap(shmdesc->addr, shmdesc->size);
1186f7df2e56Smrg        free(shmdesc);
1187f7df2e56Smrg        return BadAlloc;
1188f7df2e56Smrg    }
1189f7df2e56Smrg
1190f7df2e56Smrg    shmdesc->next = Shmsegs;
1191f7df2e56Smrg    Shmsegs = shmdesc;
1192f7df2e56Smrg
1193f7df2e56Smrg    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
1194f7df2e56Smrg        return BadAlloc;
1195f7df2e56Smrg    return Success;
1196f7df2e56Smrg}
1197f7df2e56Smrg
1198f7df2e56Smrgstatic int
1199f7df2e56Smrgshm_tmpfile(void)
1200f7df2e56Smrg{
1201f7df2e56Smrg#ifdef SHMDIR
1202f7df2e56Smrg	int	fd;
1203f7df2e56Smrg	int	flags;
1204f7df2e56Smrg	char	template[] = SHMDIR "/shmfd-XXXXXX";
1205f7df2e56Smrg#ifdef O_TMPFILE
1206f7df2e56Smrg	fd = open(SHMDIR, O_TMPFILE|O_RDWR|O_CLOEXEC|O_EXCL, 0666);
1207f7df2e56Smrg	if (fd >= 0) {
1208f7df2e56Smrg		ErrorF ("Using O_TMPFILE\n");
1209f7df2e56Smrg		return fd;
12104642e01fSmrg	}
1211f7df2e56Smrg	ErrorF ("Not using O_TMPFILE\n");
1212f7df2e56Smrg#endif
1213f7df2e56Smrg	fd = mkstemp(template);
1214f7df2e56Smrg	if (fd < 0)
1215f7df2e56Smrg		return -1;
1216f7df2e56Smrg	unlink(template);
1217f7df2e56Smrg	if (fcntl(fd, F_GETFD, &flags) >= 0) {
1218f7df2e56Smrg		flags |= FD_CLOEXEC;
1219f7df2e56Smrg		(void) fcntl(fd, F_SETFD, &flags);
122005b261ecSmrg	}
1221f7df2e56Smrg	return fd;
1222f7df2e56Smrg#else
1223f7df2e56Smrg        return -1;
1224f7df2e56Smrg#endif
1225f7df2e56Smrg}
1226f7df2e56Smrg
1227f7df2e56Smrgstatic int
1228f7df2e56SmrgProcShmCreateSegment(ClientPtr client)
1229f7df2e56Smrg{
1230f7df2e56Smrg    int fd;
1231f7df2e56Smrg    ShmDescPtr shmdesc;
1232f7df2e56Smrg    REQUEST(xShmCreateSegmentReq);
1233f7df2e56Smrg    xShmCreateSegmentReply rep = {
1234f7df2e56Smrg        .type = X_Reply,
1235f7df2e56Smrg        .nfd = 1,
1236f7df2e56Smrg        .sequenceNumber = client->sequence,
1237f7df2e56Smrg        .length = 0,
1238f7df2e56Smrg    };
1239f7df2e56Smrg
1240f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
1241f7df2e56Smrg    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1242f7df2e56Smrg        client->errorValue = stuff->readOnly;
1243f7df2e56Smrg        return BadValue;
124405b261ecSmrg    }
1245f7df2e56Smrg    fd = shm_tmpfile();
1246f7df2e56Smrg    if (fd < 0)
1247f7df2e56Smrg        return BadAlloc;
1248f7df2e56Smrg    if (ftruncate(fd, stuff->size) < 0) {
1249f7df2e56Smrg        close(fd);
1250f7df2e56Smrg        return BadAlloc;
1251f7df2e56Smrg    }
1252f7df2e56Smrg    shmdesc = malloc(sizeof(ShmDescRec));
1253f7df2e56Smrg    if (!shmdesc) {
1254f7df2e56Smrg        close(fd);
1255f7df2e56Smrg        return BadAlloc;
1256f7df2e56Smrg    }
1257f7df2e56Smrg    shmdesc->is_fd = TRUE;
1258f7df2e56Smrg    shmdesc->addr = mmap(NULL, stuff->size,
1259f7df2e56Smrg                         stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1260f7df2e56Smrg                         MAP_SHARED,
1261f7df2e56Smrg                         fd, 0);
1262f7df2e56Smrg
1263f7df2e56Smrg    if (shmdesc->addr == ((char *) -1)) {
1264f7df2e56Smrg        close(fd);
1265f7df2e56Smrg        free(shmdesc);
1266f7df2e56Smrg        return BadAccess;
1267f7df2e56Smrg    }
1268f7df2e56Smrg
1269f7df2e56Smrg    shmdesc->refcnt = 1;
1270f7df2e56Smrg    shmdesc->writable = !stuff->readOnly;
1271f7df2e56Smrg    shmdesc->size = stuff->size;
1272f7df2e56Smrg
1273f7df2e56Smrg    shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1274f7df2e56Smrg    if (!shmdesc->busfault) {
1275f7df2e56Smrg        close(fd);
1276f7df2e56Smrg        munmap(shmdesc->addr, shmdesc->size);
1277f7df2e56Smrg        free(shmdesc);
1278f7df2e56Smrg        return BadAlloc;
1279f7df2e56Smrg    }
1280f7df2e56Smrg
1281f7df2e56Smrg    shmdesc->next = Shmsegs;
1282f7df2e56Smrg    Shmsegs = shmdesc;
1283f7df2e56Smrg
1284f7df2e56Smrg    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc)) {
1285f7df2e56Smrg        close(fd);
1286f7df2e56Smrg        return BadAlloc;
1287f7df2e56Smrg    }
1288f7df2e56Smrg
1289f7df2e56Smrg    if (WriteFdToClient(client, fd, TRUE) < 0) {
1290f7df2e56Smrg        FreeResource(stuff->shmseg, RT_NONE);
1291f7df2e56Smrg        close(fd);
1292f7df2e56Smrg        return BadAlloc;
1293f7df2e56Smrg    }
1294f7df2e56Smrg    WriteToClient(client, sizeof (xShmCreateSegmentReply), &rep);
1295f7df2e56Smrg    return Success;
129605b261ecSmrg}
1297f7df2e56Smrg#endif /* SHM_FD_PASSING */
129805b261ecSmrg
129905b261ecSmrgstatic int
1300f7df2e56SmrgProcShmDispatch(ClientPtr client)
130105b261ecSmrg{
130205b261ecSmrg    REQUEST(xReq);
1303f7df2e56Smrg    switch (stuff->data) {
130405b261ecSmrg    case X_ShmQueryVersion:
1305f7df2e56Smrg        return ProcShmQueryVersion(client);
130605b261ecSmrg    case X_ShmAttach:
1307f7df2e56Smrg        return ProcShmAttach(client);
130805b261ecSmrg    case X_ShmDetach:
1309f7df2e56Smrg        return ProcShmDetach(client);
131005b261ecSmrg    case X_ShmPutImage:
131105b261ecSmrg#ifdef PANORAMIX
1312f7df2e56Smrg        if (!noPanoramiXExtension)
1313f7df2e56Smrg            return ProcPanoramiXShmPutImage(client);
131405b261ecSmrg#endif
1315f7df2e56Smrg        return ProcShmPutImage(client);
131605b261ecSmrg    case X_ShmGetImage:
131705b261ecSmrg#ifdef PANORAMIX
1318f7df2e56Smrg        if (!noPanoramiXExtension)
1319f7df2e56Smrg            return ProcPanoramiXShmGetImage(client);
132005b261ecSmrg#endif
1321f7df2e56Smrg        return ProcShmGetImage(client);
132205b261ecSmrg    case X_ShmCreatePixmap:
132305b261ecSmrg#ifdef PANORAMIX
1324f7df2e56Smrg        if (!noPanoramiXExtension)
1325f7df2e56Smrg            return ProcPanoramiXShmCreatePixmap(client);
1326f7df2e56Smrg#endif
1327f7df2e56Smrg        return ProcShmCreatePixmap(client);
1328f7df2e56Smrg#ifdef SHM_FD_PASSING
1329f7df2e56Smrg    case X_ShmAttachFd:
1330f7df2e56Smrg        return ProcShmAttachFd(client);
1331f7df2e56Smrg    case X_ShmCreateSegment:
1332f7df2e56Smrg        return ProcShmCreateSegment(client);
133305b261ecSmrg#endif
133405b261ecSmrg    default:
1335f7df2e56Smrg        return BadRequest;
133605b261ecSmrg    }
133705b261ecSmrg}
133805b261ecSmrg
133905b261ecSmrgstatic void
1340f7df2e56SmrgSShmCompletionEvent(xShmCompletionEvent * from, xShmCompletionEvent * to)
134105b261ecSmrg{
134205b261ecSmrg    to->type = from->type;
134305b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
134405b261ecSmrg    cpswapl(from->drawable, to->drawable);
134505b261ecSmrg    cpswaps(from->minorEvent, to->minorEvent);
134605b261ecSmrg    to->majorEvent = from->majorEvent;
134705b261ecSmrg    cpswapl(from->shmseg, to->shmseg);
134805b261ecSmrg    cpswapl(from->offset, to->offset);
134905b261ecSmrg}
135005b261ecSmrg
135105b261ecSmrgstatic int
13524642e01fSmrgSProcShmQueryVersion(ClientPtr client)
135305b261ecSmrg{
135405b261ecSmrg    REQUEST(xShmQueryVersionReq);
135505b261ecSmrg
1356f7df2e56Smrg    swaps(&stuff->length);
135705b261ecSmrg    return ProcShmQueryVersion(client);
135805b261ecSmrg}
135905b261ecSmrg
136005b261ecSmrgstatic int
13614642e01fSmrgSProcShmAttach(ClientPtr client)
136205b261ecSmrg{
136305b261ecSmrg    REQUEST(xShmAttachReq);
1364f7df2e56Smrg    swaps(&stuff->length);
136505b261ecSmrg    REQUEST_SIZE_MATCH(xShmAttachReq);
1366f7df2e56Smrg    swapl(&stuff->shmseg);
1367f7df2e56Smrg    swapl(&stuff->shmid);
136805b261ecSmrg    return ProcShmAttach(client);
136905b261ecSmrg}
137005b261ecSmrg
137105b261ecSmrgstatic int
13724642e01fSmrgSProcShmDetach(ClientPtr client)
137305b261ecSmrg{
137405b261ecSmrg    REQUEST(xShmDetachReq);
1375f7df2e56Smrg    swaps(&stuff->length);
137605b261ecSmrg    REQUEST_SIZE_MATCH(xShmDetachReq);
1377f7df2e56Smrg    swapl(&stuff->shmseg);
137805b261ecSmrg    return ProcShmDetach(client);
137905b261ecSmrg}
138005b261ecSmrg
138105b261ecSmrgstatic int
13824642e01fSmrgSProcShmPutImage(ClientPtr client)
138305b261ecSmrg{
138405b261ecSmrg    REQUEST(xShmPutImageReq);
1385f7df2e56Smrg    swaps(&stuff->length);
138605b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
1387f7df2e56Smrg    swapl(&stuff->drawable);
1388f7df2e56Smrg    swapl(&stuff->gc);
1389f7df2e56Smrg    swaps(&stuff->totalWidth);
1390f7df2e56Smrg    swaps(&stuff->totalHeight);
1391f7df2e56Smrg    swaps(&stuff->srcX);
1392f7df2e56Smrg    swaps(&stuff->srcY);
1393f7df2e56Smrg    swaps(&stuff->srcWidth);
1394f7df2e56Smrg    swaps(&stuff->srcHeight);
1395f7df2e56Smrg    swaps(&stuff->dstX);
1396f7df2e56Smrg    swaps(&stuff->dstY);
1397f7df2e56Smrg    swapl(&stuff->shmseg);
1398f7df2e56Smrg    swapl(&stuff->offset);
139905b261ecSmrg    return ProcShmPutImage(client);
140005b261ecSmrg}
140105b261ecSmrg
140205b261ecSmrgstatic int
14034642e01fSmrgSProcShmGetImage(ClientPtr client)
140405b261ecSmrg{
140505b261ecSmrg    REQUEST(xShmGetImageReq);
1406f7df2e56Smrg    swaps(&stuff->length);
140705b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
1408f7df2e56Smrg    swapl(&stuff->drawable);
1409f7df2e56Smrg    swaps(&stuff->x);
1410f7df2e56Smrg    swaps(&stuff->y);
1411f7df2e56Smrg    swaps(&stuff->width);
1412f7df2e56Smrg    swaps(&stuff->height);
1413f7df2e56Smrg    swapl(&stuff->planeMask);
1414f7df2e56Smrg    swapl(&stuff->shmseg);
1415f7df2e56Smrg    swapl(&stuff->offset);
141605b261ecSmrg    return ProcShmGetImage(client);
141705b261ecSmrg}
141805b261ecSmrg
141905b261ecSmrgstatic int
14204642e01fSmrgSProcShmCreatePixmap(ClientPtr client)
142105b261ecSmrg{
142205b261ecSmrg    REQUEST(xShmCreatePixmapReq);
1423f7df2e56Smrg    swaps(&stuff->length);
142405b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1425f7df2e56Smrg    swapl(&stuff->pid);
1426f7df2e56Smrg    swapl(&stuff->drawable);
1427f7df2e56Smrg    swaps(&stuff->width);
1428f7df2e56Smrg    swaps(&stuff->height);
1429f7df2e56Smrg    swapl(&stuff->shmseg);
1430f7df2e56Smrg    swapl(&stuff->offset);
143105b261ecSmrg    return ProcShmCreatePixmap(client);
143205b261ecSmrg}
143305b261ecSmrg
1434f7df2e56Smrg#ifdef SHM_FD_PASSING
143505b261ecSmrgstatic int
1436f7df2e56SmrgSProcShmAttachFd(ClientPtr client)
1437f7df2e56Smrg{
1438f7df2e56Smrg    REQUEST(xShmAttachFdReq);
1439f7df2e56Smrg    SetReqFds(client, 1);
1440f7df2e56Smrg    swaps(&stuff->length);
1441f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmAttachFdReq);
1442f7df2e56Smrg    swapl(&stuff->shmseg);
1443f7df2e56Smrg    return ProcShmAttachFd(client);
1444f7df2e56Smrg}
1445f7df2e56Smrg
1446f7df2e56Smrgstatic int
1447f7df2e56SmrgSProcShmCreateSegment(ClientPtr client)
1448f7df2e56Smrg{
1449f7df2e56Smrg    REQUEST(xShmCreateSegmentReq);
1450f7df2e56Smrg    swaps(&stuff->length);
1451f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
1452f7df2e56Smrg    swapl(&stuff->shmseg);
1453f7df2e56Smrg    swapl(&stuff->size);
1454f7df2e56Smrg    return ProcShmCreateSegment(client);
1455f7df2e56Smrg}
1456f7df2e56Smrg#endif  /* SHM_FD_PASSING */
1457f7df2e56Smrg
1458f7df2e56Smrgstatic int
1459f7df2e56SmrgSProcShmDispatch(ClientPtr client)
146005b261ecSmrg{
146105b261ecSmrg    REQUEST(xReq);
1462f7df2e56Smrg    switch (stuff->data) {
146305b261ecSmrg    case X_ShmQueryVersion:
1464f7df2e56Smrg        return SProcShmQueryVersion(client);
146505b261ecSmrg    case X_ShmAttach:
1466f7df2e56Smrg        return SProcShmAttach(client);
146705b261ecSmrg    case X_ShmDetach:
1468f7df2e56Smrg        return SProcShmDetach(client);
146905b261ecSmrg    case X_ShmPutImage:
1470f7df2e56Smrg        return SProcShmPutImage(client);
147105b261ecSmrg    case X_ShmGetImage:
1472f7df2e56Smrg        return SProcShmGetImage(client);
147305b261ecSmrg    case X_ShmCreatePixmap:
1474f7df2e56Smrg        return SProcShmCreatePixmap(client);
1475f7df2e56Smrg#ifdef SHM_FD_PASSING
1476f7df2e56Smrg    case X_ShmAttachFd:
1477f7df2e56Smrg        return SProcShmAttachFd(client);
1478f7df2e56Smrg    case X_ShmCreateSegment:
1479f7df2e56Smrg        return SProcShmCreateSegment(client);
1480f7df2e56Smrg#endif
148105b261ecSmrg    default:
1482f7df2e56Smrg        return BadRequest;
148305b261ecSmrg    }
148405b261ecSmrg}
148565b04b38Smrg
148665b04b38Smrgvoid
1487f7df2e56SmrgShmExtensionInit(void)
148865b04b38Smrg{
148965b04b38Smrg    ExtensionEntry *extEntry;
149065b04b38Smrg    int i;
149165b04b38Smrg
149265b04b38Smrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL
1493f7df2e56Smrg    if (!CheckForShmSyscall()) {
1494f7df2e56Smrg        ErrorF("MIT-SHM extension disabled due to lack of kernel support\n");
1495f7df2e56Smrg        return;
149665b04b38Smrg    }
149765b04b38Smrg#endif
149865b04b38Smrg
149965b04b38Smrg    if (!ShmRegisterPrivates())
1500f7df2e56Smrg        return;
150165b04b38Smrg
150265b04b38Smrg    sharedPixmaps = xFalse;
150365b04b38Smrg    {
1504f7df2e56Smrg        sharedPixmaps = xTrue;
1505f7df2e56Smrg        for (i = 0; i < screenInfo.numScreens; i++) {
1506f7df2e56Smrg            ShmScrPrivateRec *screen_priv =
1507f7df2e56Smrg                ShmInitScreenPriv(screenInfo.screens[i]);
1508f7df2e56Smrg            if (!screen_priv->shmFuncs)
1509f7df2e56Smrg                screen_priv->shmFuncs = &miFuncs;
1510f7df2e56Smrg            if (!screen_priv->shmFuncs->CreatePixmap)
1511f7df2e56Smrg                sharedPixmaps = xFalse;
1512f7df2e56Smrg        }
1513f7df2e56Smrg        if (sharedPixmaps)
1514f7df2e56Smrg            for (i = 0; i < screenInfo.numScreens; i++) {
1515f7df2e56Smrg                ShmScrPrivateRec *screen_priv =
1516f7df2e56Smrg                    ShmGetScreenPriv(screenInfo.screens[i]);
1517f7df2e56Smrg                screen_priv->destroyPixmap =
1518f7df2e56Smrg                    screenInfo.screens[i]->DestroyPixmap;
1519f7df2e56Smrg                screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap;
1520f7df2e56Smrg            }
152165b04b38Smrg    }
152265b04b38Smrg    ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg");
152365b04b38Smrg    if (ShmSegType &&
1524f7df2e56Smrg        (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors,
1525f7df2e56Smrg                                 ProcShmDispatch, SProcShmDispatch,
1526f7df2e56Smrg                                 ShmResetProc, StandardMinorOpcode))) {
1527f7df2e56Smrg        ShmReqCode = (unsigned char) extEntry->base;
1528f7df2e56Smrg        ShmCompletionCode = extEntry->eventBase;
1529f7df2e56Smrg        BadShmSegCode = extEntry->errorBase;
1530f7df2e56Smrg        SetResourceTypeErrorValue(ShmSegType, BadShmSegCode);
1531f7df2e56Smrg        EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent;
153265b04b38Smrg    }
153365b04b38Smrg}
1534