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>
384e185dc0Smrg#ifdef HAVE_MEMFD_CREATE
394e185dc0Smrg#include <sys/mman.h>
404e185dc0Smrg#endif
4105b261ecSmrg#include <unistd.h>
4205b261ecSmrg#include <sys/stat.h>
43f7df2e56Smrg#include <fcntl.h>
4405b261ecSmrg#include <X11/X.h>
4505b261ecSmrg#include <X11/Xproto.h>
4605b261ecSmrg#include "misc.h"
4705b261ecSmrg#include "os.h"
4805b261ecSmrg#include "dixstruct.h"
4905b261ecSmrg#include "resource.h"
5005b261ecSmrg#include "scrnintstr.h"
5105b261ecSmrg#include "windowstr.h"
5205b261ecSmrg#include "pixmapstr.h"
5305b261ecSmrg#include "gcstruct.h"
5405b261ecSmrg#include "extnsionst.h"
5505b261ecSmrg#include "servermd.h"
564642e01fSmrg#include "shmint.h"
574642e01fSmrg#include "xace.h"
58684baedfSmrg#include <X11/extensions/shmproto.h>
5905b261ecSmrg#include <X11/Xfuncproto.h>
60f7df2e56Smrg#include <sys/mman.h>
614202a189Smrg#include "protocol-versions.h"
62f7df2e56Smrg#include "busfault.h"
6305b261ecSmrg
644642e01fSmrg/* Needed for Solaris cross-zone shared memory extension */
654642e01fSmrg#ifdef HAVE_SHMCTL64
664642e01fSmrg#include <sys/ipc_impl.h>
674642e01fSmrg#define SHMSTAT(id, buf)	shmctl64(id, IPC_STAT64, buf)
684642e01fSmrg#define SHMSTAT_TYPE 		struct shmid_ds64
694642e01fSmrg#define SHMPERM_TYPE 		struct ipc_perm64
704642e01fSmrg#define SHM_PERM(buf) 		buf.shmx_perm
714642e01fSmrg#define SHM_SEGSZ(buf)		buf.shmx_segsz
724642e01fSmrg#define SHMPERM_UID(p)		p->ipcx_uid
734642e01fSmrg#define SHMPERM_CUID(p)		p->ipcx_cuid
744642e01fSmrg#define SHMPERM_GID(p)		p->ipcx_gid
754642e01fSmrg#define SHMPERM_CGID(p)		p->ipcx_cgid
764642e01fSmrg#define SHMPERM_MODE(p)		p->ipcx_mode
774642e01fSmrg#define SHMPERM_ZONEID(p)	p->ipcx_zoneid
784642e01fSmrg#else
794642e01fSmrg#define SHMSTAT(id, buf) 	shmctl(id, IPC_STAT, buf)
804642e01fSmrg#define SHMSTAT_TYPE 		struct shmid_ds
814642e01fSmrg#define SHMPERM_TYPE 		struct ipc_perm
824642e01fSmrg#define SHM_PERM(buf) 		buf.shm_perm
834642e01fSmrg#define SHM_SEGSZ(buf)		buf.shm_segsz
844642e01fSmrg#define SHMPERM_UID(p)		p->uid
854642e01fSmrg#define SHMPERM_CUID(p)		p->cuid
864642e01fSmrg#define SHMPERM_GID(p)		p->gid
874642e01fSmrg#define SHMPERM_CGID(p)		p->cgid
884642e01fSmrg#define SHMPERM_MODE(p)		p->mode
894642e01fSmrg#endif
904642e01fSmrg
9105b261ecSmrg#ifdef PANORAMIX
9205b261ecSmrg#include "panoramiX.h"
9305b261ecSmrg#include "panoramiXsrv.h"
9405b261ecSmrg#endif
9505b261ecSmrg
96f7df2e56Smrg#include "extinit.h"
9705b261ecSmrg
984202a189Smrgtypedef struct _ShmScrPrivateRec {
994202a189Smrg    CloseScreenProcPtr CloseScreen;
1004202a189Smrg    ShmFuncsPtr shmFuncs;
1014202a189Smrg    DestroyPixmapProcPtr destroyPixmap;
1024202a189Smrg} ShmScrPrivateRec;
1034202a189Smrg
10405b261ecSmrgstatic PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS);
105f7df2e56Smrgstatic int ShmDetachSegment(void *value, XID shmseg);
106f7df2e56Smrgstatic void ShmResetProc(ExtensionEntry *extEntry);
107f7df2e56Smrgstatic void SShmCompletionEvent(xShmCompletionEvent *from,
108f7df2e56Smrg                                xShmCompletionEvent *to);
10905b261ecSmrg
110f7df2e56Smrgstatic Bool ShmDestroyPixmap(PixmapPtr pPixmap);
11105b261ecSmrg
11205b261ecSmrgstatic unsigned char ShmReqCode;
1134202a189Smrgint ShmCompletionCode;
1144202a189Smrgint BadShmSegCode;
1154202a189SmrgRESTYPE ShmSegType;
11605b261ecSmrgstatic ShmDescPtr Shmsegs;
11705b261ecSmrgstatic Bool sharedPixmaps;
1184202a189Smrgstatic DevPrivateKeyRec shmScrPrivateKeyRec;
119f7df2e56Smrg
1204202a189Smrg#define shmScrPrivateKey (&shmScrPrivateKeyRec)
1214202a189Smrgstatic DevPrivateKeyRec shmPixmapPrivateKeyRec;
122f7df2e56Smrg
1234202a189Smrg#define shmPixmapPrivateKey (&shmPixmapPrivateKeyRec)
124f7df2e56Smrgstatic ShmFuncs miFuncs = { NULL, NULL };
125f7df2e56Smrgstatic ShmFuncs fbFuncs = { fbShmCreatePixmap, NULL };
12605b261ecSmrg
1274202a189Smrg#define ShmGetScreenPriv(s) ((ShmScrPrivateRec *)dixLookupPrivate(&(s)->devPrivates, shmScrPrivateKey))
1284202a189Smrg
12905b261ecSmrg#define VERIFY_SHMSEG(shmseg,shmdesc,client) \
13005b261ecSmrg{ \
131f7df2e56Smrg    int tmprc; \
132f7df2e56Smrg    tmprc = dixLookupResourceByType((void **)&(shmdesc), shmseg, ShmSegType, \
133f7df2e56Smrg                                    client, DixReadAccess); \
134f7df2e56Smrg    if (tmprc != Success) \
135f7df2e56Smrg	return tmprc; \
13605b261ecSmrg}
13705b261ecSmrg
13805b261ecSmrg#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \
13905b261ecSmrg{ \
14005b261ecSmrg    VERIFY_SHMSEG(shmseg, shmdesc, client); \
14105b261ecSmrg    if ((offset & 3) || (offset > shmdesc->size)) \
14205b261ecSmrg    { \
14305b261ecSmrg	client->errorValue = offset; \
14405b261ecSmrg	return BadValue; \
14505b261ecSmrg    } \
14605b261ecSmrg    if (needwrite && !shmdesc->writable) \
14705b261ecSmrg	return BadAccess; \
14805b261ecSmrg}
14905b261ecSmrg
15005b261ecSmrg#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \
15105b261ecSmrg{ \
15205b261ecSmrg    if ((offset + len) > shmdesc->size) \
15305b261ecSmrg    { \
15405b261ecSmrg	return BadAccess; \
15505b261ecSmrg    } \
15605b261ecSmrg}
15705b261ecSmrg
15805b261ecSmrg#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
15905b261ecSmrg
16005b261ecSmrgstatic Bool badSysCall = FALSE;
16105b261ecSmrg
16205b261ecSmrgstatic void
1634642e01fSmrgSigSysHandler(int signo)
16405b261ecSmrg{
16505b261ecSmrg    badSysCall = TRUE;
16605b261ecSmrg}
16705b261ecSmrg
168f7df2e56Smrgstatic Bool
169f7df2e56SmrgCheckForShmSyscall(void)
17005b261ecSmrg{
171f7df2e56Smrg    void (*oldHandler) (int);
17205b261ecSmrg    int shmid = -1;
17305b261ecSmrg
17405b261ecSmrg    /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
1757e31ba66Smrg    oldHandler = OsSignal(SIGSYS, SigSysHandler);
17605b261ecSmrg
17705b261ecSmrg    badSysCall = FALSE;
17805b261ecSmrg    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
17905b261ecSmrg
180f7df2e56Smrg    if (shmid != -1) {
18105b261ecSmrg        /* Successful allocation - clean up */
182f7df2e56Smrg        shmctl(shmid, IPC_RMID, NULL);
18305b261ecSmrg    }
184f7df2e56Smrg    else {
18505b261ecSmrg        /* Allocation failed */
18605b261ecSmrg        badSysCall = TRUE;
18705b261ecSmrg    }
1887e31ba66Smrg    OsSignal(SIGSYS, oldHandler);
1894202a189Smrg    return !badSysCall;
19005b261ecSmrg}
19105b261ecSmrg
19205b261ecSmrg#define MUST_CHECK_FOR_SHM_SYSCALL
19305b261ecSmrg
19405b261ecSmrg#endif
19505b261ecSmrg
1964202a189Smrgstatic Bool
197f7df2e56SmrgShmCloseScreen(ScreenPtr pScreen)
1984202a189Smrg{
1994202a189Smrg    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
200f7df2e56Smrg
2014202a189Smrg    pScreen->CloseScreen = screen_priv->CloseScreen;
2024202a189Smrg    dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL);
2034202a189Smrg    free(screen_priv);
204f7df2e56Smrg    return (*pScreen->CloseScreen) (pScreen);
2054202a189Smrg}
2064202a189Smrg
2074202a189Smrgstatic ShmScrPrivateRec *
2084202a189SmrgShmInitScreenPriv(ScreenPtr pScreen)
2094202a189Smrg{
2104202a189Smrg    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
211f7df2e56Smrg
212f7df2e56Smrg    if (!screen_priv) {
213f7df2e56Smrg        screen_priv = calloc(1, sizeof(ShmScrPrivateRec));
214f7df2e56Smrg        screen_priv->CloseScreen = pScreen->CloseScreen;
215f7df2e56Smrg        dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv);
216f7df2e56Smrg        pScreen->CloseScreen = ShmCloseScreen;
2174202a189Smrg    }
2184202a189Smrg    return screen_priv;
2194202a189Smrg}
2204202a189Smrg
2214202a189Smrgstatic Bool
2224202a189SmrgShmRegisterPrivates(void)
2234202a189Smrg{
2244202a189Smrg    if (!dixRegisterPrivateKey(&shmScrPrivateKeyRec, PRIVATE_SCREEN, 0))
225f7df2e56Smrg        return FALSE;
2264202a189Smrg    if (!dixRegisterPrivateKey(&shmPixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
227f7df2e56Smrg        return FALSE;
2284202a189Smrg    return TRUE;
2294202a189Smrg}
2304202a189Smrg
231f7df2e56Smrg /*ARGSUSED*/ static void
232f7df2e56SmrgShmResetProc(ExtensionEntry * extEntry)
23305b261ecSmrg{
23405b261ecSmrg    int i;
235f7df2e56Smrg
2364202a189Smrg    for (i = 0; i < screenInfo.numScreens; i++)
237f7df2e56Smrg        ShmRegisterFuncs(screenInfo.screens[i], NULL);
23805b261ecSmrg}
23905b261ecSmrg
2404202a189Smrgvoid
2414642e01fSmrgShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs)
24205b261ecSmrg{
2434202a189Smrg    if (!ShmRegisterPrivates())
244f7df2e56Smrg        return;
2454202a189Smrg    ShmInitScreenPriv(pScreen)->shmFuncs = funcs;
24605b261ecSmrg}
24705b261ecSmrg
24805b261ecSmrgstatic Bool
249f7df2e56SmrgShmDestroyPixmap(PixmapPtr pPixmap)
25005b261ecSmrg{
251f7df2e56Smrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
2524202a189Smrg    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
253f7df2e56Smrg    void *shmdesc = NULL;
254f7df2e56Smrg    Bool ret;
255f7df2e56Smrg
25605b261ecSmrg    if (pPixmap->refcnt == 1)
257f7df2e56Smrg        shmdesc = dixLookupPrivate(&pPixmap->devPrivates, shmPixmapPrivateKey);
258f7df2e56Smrg
2594202a189Smrg    pScreen->DestroyPixmap = screen_priv->destroyPixmap;
26005b261ecSmrg    ret = (*pScreen->DestroyPixmap) (pPixmap);
2614202a189Smrg    screen_priv->destroyPixmap = pScreen->DestroyPixmap;
26205b261ecSmrg    pScreen->DestroyPixmap = ShmDestroyPixmap;
263f7df2e56Smrg
264f7df2e56Smrg    if (shmdesc)
265f7df2e56Smrg	ShmDetachSegment(shmdesc, 0);
266f7df2e56Smrg
26705b261ecSmrg    return ret;
26805b261ecSmrg}
26905b261ecSmrg
2704202a189Smrgvoid
2714642e01fSmrgShmRegisterFbFuncs(ScreenPtr pScreen)
27205b261ecSmrg{
2734202a189Smrg    ShmRegisterFuncs(pScreen, &fbFuncs);
27405b261ecSmrg}
27505b261ecSmrg
27605b261ecSmrgstatic int
2774642e01fSmrgProcShmQueryVersion(ClientPtr client)
27805b261ecSmrg{
279f7df2e56Smrg    xShmQueryVersionReply rep = {
280f7df2e56Smrg        .type = X_Reply,
281f7df2e56Smrg        .sharedPixmaps = sharedPixmaps,
282f7df2e56Smrg        .sequenceNumber = client->sequence,
283f7df2e56Smrg        .length = 0,
284f7df2e56Smrg        .majorVersion = SERVER_SHM_MAJOR_VERSION,
285f7df2e56Smrg        .minorVersion = SERVER_SHM_MINOR_VERSION,
286f7df2e56Smrg        .uid = geteuid(),
287f7df2e56Smrg        .gid = getegid(),
288f7df2e56Smrg        .pixmapFormat = sharedPixmaps ? ZPixmap : 0
289f7df2e56Smrg    };
29005b261ecSmrg
29105b261ecSmrg    REQUEST_SIZE_MATCH(xShmQueryVersionReq);
292f7df2e56Smrg
29305b261ecSmrg    if (client->swapped) {
294f7df2e56Smrg        swaps(&rep.sequenceNumber);
295f7df2e56Smrg        swapl(&rep.length);
296f7df2e56Smrg        swaps(&rep.majorVersion);
297f7df2e56Smrg        swaps(&rep.minorVersion);
298f7df2e56Smrg        swaps(&rep.uid);
299f7df2e56Smrg        swaps(&rep.gid);
300f7df2e56Smrg    }
301f7df2e56Smrg    WriteToClient(client, sizeof(xShmQueryVersionReply), &rep);
3024202a189Smrg    return Success;
30305b261ecSmrg}
30405b261ecSmrg
30505b261ecSmrg/*
3065a112b11Smrg * Simulate the access() system call for a shared memory segment,
3075a112b11Smrg * using the credentials from the client if available.
30805b261ecSmrg */
30905b261ecSmrgstatic int
310f7df2e56Smrgshm_access(ClientPtr client, SHMPERM_TYPE * perm, int readonly)
31105b261ecSmrg{
31205b261ecSmrg    int uid, gid;
31305b261ecSmrg    mode_t mask;
3144642e01fSmrg    int uidset = 0, gidset = 0;
3154642e01fSmrg    LocalClientCredRec *lcc;
316f7df2e56Smrg
3174642e01fSmrg    if (GetLocalClientCreds(client, &lcc) != -1) {
31805b261ecSmrg
319f7df2e56Smrg        if (lcc->fieldsSet & LCC_UID_SET) {
320f7df2e56Smrg            uid = lcc->euid;
321f7df2e56Smrg            uidset = 1;
322f7df2e56Smrg        }
323f7df2e56Smrg        if (lcc->fieldsSet & LCC_GID_SET) {
324f7df2e56Smrg            gid = lcc->egid;
325f7df2e56Smrg            gidset = 1;
326f7df2e56Smrg        }
3274642e01fSmrg
3284642e01fSmrg#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID)
329f7df2e56Smrg        if (((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1)
330f7df2e56Smrg            || (lcc->zoneid != SHMPERM_ZONEID(perm))) {
331f7df2e56Smrg            uidset = 0;
332f7df2e56Smrg            gidset = 0;
333f7df2e56Smrg        }
3344642e01fSmrg#endif
335f7df2e56Smrg        FreeLocalClientCreds(lcc);
336f7df2e56Smrg
337f7df2e56Smrg        if (uidset) {
338f7df2e56Smrg            /* User id 0 always gets access */
339f7df2e56Smrg            if (uid == 0) {
340f7df2e56Smrg                return 0;
341f7df2e56Smrg            }
342f7df2e56Smrg            /* Check the owner */
343f7df2e56Smrg            if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) {
344f7df2e56Smrg                mask = S_IRUSR;
345f7df2e56Smrg                if (!readonly) {
346f7df2e56Smrg                    mask |= S_IWUSR;
347f7df2e56Smrg                }
348f7df2e56Smrg                return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
349f7df2e56Smrg            }
350f7df2e56Smrg        }
351f7df2e56Smrg
352f7df2e56Smrg        if (gidset) {
353f7df2e56Smrg            /* Check the group */
354f7df2e56Smrg            if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) {
355f7df2e56Smrg                mask = S_IRGRP;
356f7df2e56Smrg                if (!readonly) {
357f7df2e56Smrg                    mask |= S_IWGRP;
358f7df2e56Smrg                }
359f7df2e56Smrg                return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
360f7df2e56Smrg            }
361f7df2e56Smrg        }
36205b261ecSmrg    }
36305b261ecSmrg    /* Otherwise, check everyone else */
36405b261ecSmrg    mask = S_IROTH;
36505b261ecSmrg    if (!readonly) {
366f7df2e56Smrg        mask |= S_IWOTH;
36705b261ecSmrg    }
3684642e01fSmrg    return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
36905b261ecSmrg}
37005b261ecSmrg
37105b261ecSmrgstatic int
3724642e01fSmrgProcShmAttach(ClientPtr client)
37305b261ecSmrg{
3744642e01fSmrg    SHMSTAT_TYPE buf;
37505b261ecSmrg    ShmDescPtr shmdesc;
376f7df2e56Smrg
37705b261ecSmrg    REQUEST(xShmAttachReq);
37805b261ecSmrg
37905b261ecSmrg    REQUEST_SIZE_MATCH(xShmAttachReq);
38005b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
381f7df2e56Smrg    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
382f7df2e56Smrg        client->errorValue = stuff->readOnly;
3834202a189Smrg        return BadValue;
38405b261ecSmrg    }
385f7df2e56Smrg    for (shmdesc = Shmsegs; shmdesc; shmdesc = shmdesc->next) {
386f7df2e56Smrg        if (!SHMDESC_IS_FD(shmdesc) && shmdesc->shmid == stuff->shmid)
387f7df2e56Smrg            break;
38805b261ecSmrg    }
389f7df2e56Smrg    if (shmdesc) {
390f7df2e56Smrg        if (!stuff->readOnly && !shmdesc->writable)
391f7df2e56Smrg            return BadAccess;
392f7df2e56Smrg        shmdesc->refcnt++;
393f7df2e56Smrg    }
394f7df2e56Smrg    else {
395f7df2e56Smrg        shmdesc = malloc(sizeof(ShmDescRec));
396f7df2e56Smrg        if (!shmdesc)
397f7df2e56Smrg            return BadAlloc;
398f7df2e56Smrg#ifdef SHM_FD_PASSING
399f7df2e56Smrg        shmdesc->is_fd = FALSE;
400f7df2e56Smrg#endif
401f7df2e56Smrg        shmdesc->addr = shmat(stuff->shmid, 0,
402f7df2e56Smrg                              stuff->readOnly ? SHM_RDONLY : 0);
403f7df2e56Smrg        if ((shmdesc->addr == ((char *) -1)) || SHMSTAT(stuff->shmid, &buf)) {
404f7df2e56Smrg            free(shmdesc);
405f7df2e56Smrg            return BadAccess;
406f7df2e56Smrg        }
407f7df2e56Smrg
408f7df2e56Smrg        /* The attach was performed with root privs. We must
409f7df2e56Smrg         * do manual checking of access rights for the credentials
410f7df2e56Smrg         * of the client */
411f7df2e56Smrg
412f7df2e56Smrg        if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) {
413f7df2e56Smrg            shmdt(shmdesc->addr);
414f7df2e56Smrg            free(shmdesc);
415f7df2e56Smrg            return BadAccess;
416f7df2e56Smrg        }
417f7df2e56Smrg
418f7df2e56Smrg        shmdesc->shmid = stuff->shmid;
419f7df2e56Smrg        shmdesc->refcnt = 1;
420f7df2e56Smrg        shmdesc->writable = !stuff->readOnly;
421f7df2e56Smrg        shmdesc->size = SHM_SEGSZ(buf);
422f7df2e56Smrg        shmdesc->next = Shmsegs;
423f7df2e56Smrg        Shmsegs = shmdesc;
42405b261ecSmrg    }
425f7df2e56Smrg    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
426f7df2e56Smrg        return BadAlloc;
4274202a189Smrg    return Success;
42805b261ecSmrg}
42905b261ecSmrg
430f7df2e56Smrg /*ARGSUSED*/ static int
431f7df2e56SmrgShmDetachSegment(void *value, /* must conform to DeleteType */
432f7df2e56Smrg                 XID unused)
43305b261ecSmrg{
434f7df2e56Smrg    ShmDescPtr shmdesc = (ShmDescPtr) value;
43505b261ecSmrg    ShmDescPtr *prev;
43605b261ecSmrg
43705b261ecSmrg    if (--shmdesc->refcnt)
438f7df2e56Smrg        return TRUE;
439f7df2e56Smrg#if SHM_FD_PASSING
440f7df2e56Smrg    if (shmdesc->is_fd) {
441f7df2e56Smrg        if (shmdesc->busfault)
442f7df2e56Smrg            busfault_unregister(shmdesc->busfault);
443f7df2e56Smrg        munmap(shmdesc->addr, shmdesc->size);
444f7df2e56Smrg    } else
445f7df2e56Smrg#endif
446f7df2e56Smrg        shmdt(shmdesc->addr);
447f7df2e56Smrg    for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next);
44805b261ecSmrg    *prev = shmdesc->next;
4494202a189Smrg    free(shmdesc);
45005b261ecSmrg    return Success;
45105b261ecSmrg}
45205b261ecSmrg
45305b261ecSmrgstatic int
4544642e01fSmrgProcShmDetach(ClientPtr client)
45505b261ecSmrg{
45605b261ecSmrg    ShmDescPtr shmdesc;
457f7df2e56Smrg
45805b261ecSmrg    REQUEST(xShmDetachReq);
45905b261ecSmrg
46005b261ecSmrg    REQUEST_SIZE_MATCH(xShmDetachReq);
46105b261ecSmrg    VERIFY_SHMSEG(stuff->shmseg, shmdesc, client);
46205b261ecSmrg    FreeResource(stuff->shmseg, RT_NONE);
4634202a189Smrg    return Success;
46405b261ecSmrg}
46505b261ecSmrg
4664642e01fSmrg/*
4674642e01fSmrg * If the given request doesn't exactly match PutImage's constraints,
4684642e01fSmrg * wrap the image in a scratch pixmap header and let CopyArea sort it out.
4694642e01fSmrg */
47005b261ecSmrgstatic void
4714642e01fSmrgdoShmPutImage(DrawablePtr dst, GCPtr pGC,
472f7df2e56Smrg              int depth, unsigned int format,
473f7df2e56Smrg              int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
474f7df2e56Smrg              char *data)
47505b261ecSmrg{
4764642e01fSmrg    PixmapPtr pPixmap;
4774202a189Smrg
47845bb0b75Smrg    if (format == ZPixmap || (format == XYPixmap && depth == 1)) {
479f7df2e56Smrg        pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth,
480f7df2e56Smrg                                         BitsPerPixel(depth),
481f7df2e56Smrg                                         PixmapBytePad(w, depth), data);
482f7df2e56Smrg        if (!pPixmap)
483f7df2e56Smrg            return;
484f7df2e56Smrg        pGC->ops->CopyArea((DrawablePtr) pPixmap, dst, pGC, sx, sy, sw, sh, dx,
485f7df2e56Smrg                           dy);
486f7df2e56Smrg        FreeScratchPixmapHeader(pPixmap);
487f7df2e56Smrg    }
488f7df2e56Smrg    else {
489f7df2e56Smrg        GCPtr putGC = GetScratchGC(depth, dst->pScreen);
490f7df2e56Smrg
491f7df2e56Smrg        if (!putGC)
492f7df2e56Smrg            return;
493f7df2e56Smrg
494f7df2e56Smrg        pPixmap = (*dst->pScreen->CreatePixmap) (dst->pScreen, sw, sh, depth,
495f7df2e56Smrg                                                 CREATE_PIXMAP_USAGE_SCRATCH);
496f7df2e56Smrg        if (!pPixmap) {
497f7df2e56Smrg            FreeScratchGC(putGC);
498f7df2e56Smrg            return;
499f7df2e56Smrg        }
500f7df2e56Smrg        ValidateGC(&pPixmap->drawable, putGC);
501f7df2e56Smrg        (*putGC->ops->PutImage) (&pPixmap->drawable, putGC, depth, -sx, -sy, w,
502f7df2e56Smrg                                 h, 0,
503f7df2e56Smrg                                 (format == XYPixmap) ? XYPixmap : ZPixmap,
504f7df2e56Smrg                                 data);
505f7df2e56Smrg        FreeScratchGC(putGC);
506f7df2e56Smrg        if (format == XYBitmap)
507f7df2e56Smrg            (void) (*pGC->ops->CopyPlane) (&pPixmap->drawable, dst, pGC, 0, 0,
508f7df2e56Smrg                                           sw, sh, dx, dy, 1L);
509f7df2e56Smrg        else
510f7df2e56Smrg            (void) (*pGC->ops->CopyArea) (&pPixmap->drawable, dst, pGC, 0, 0,
511f7df2e56Smrg                                          sw, sh, dx, dy);
512f7df2e56Smrg        (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap);
5134202a189Smrg    }
51405b261ecSmrg}
51505b261ecSmrg
51665b04b38Smrgstatic int
51765b04b38SmrgProcShmPutImage(ClientPtr client)
51805b261ecSmrg{
51965b04b38Smrg    GCPtr pGC;
52065b04b38Smrg    DrawablePtr pDraw;
52165b04b38Smrg    long length;
52265b04b38Smrg    ShmDescPtr shmdesc;
523f7df2e56Smrg
52405b261ecSmrg    REQUEST(xShmPutImageReq);
52565b04b38Smrg
52605b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
52765b04b38Smrg    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
52865b04b38Smrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client);
52965b04b38Smrg    if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse))
530f7df2e56Smrg        return BadValue;
531f7df2e56Smrg    if (stuff->format == XYBitmap) {
53265b04b38Smrg        if (stuff->depth != 1)
53365b04b38Smrg            return BadMatch;
53465b04b38Smrg        length = PixmapBytePad(stuff->totalWidth, 1);
53565b04b38Smrg    }
536f7df2e56Smrg    else if (stuff->format == XYPixmap) {
53765b04b38Smrg        if (pDraw->depth != stuff->depth)
53865b04b38Smrg            return BadMatch;
53965b04b38Smrg        length = PixmapBytePad(stuff->totalWidth, 1);
540f7df2e56Smrg        length *= stuff->depth;
54165b04b38Smrg    }
542f7df2e56Smrg    else if (stuff->format == ZPixmap) {
54365b04b38Smrg        if (pDraw->depth != stuff->depth)
54465b04b38Smrg            return BadMatch;
54565b04b38Smrg        length = PixmapBytePad(stuff->totalWidth, stuff->depth);
54665b04b38Smrg    }
547f7df2e56Smrg    else {
548f7df2e56Smrg        client->errorValue = stuff->format;
54965b04b38Smrg        return BadValue;
55065b04b38Smrg    }
55105b261ecSmrg
55265b04b38Smrg    /*
55365b04b38Smrg     * There's a potential integer overflow in this check:
55465b04b38Smrg     * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight,
55565b04b38Smrg     *                client);
55665b04b38Smrg     * the version below ought to avoid it
55765b04b38Smrg     */
55865b04b38Smrg    if (stuff->totalHeight != 0 &&
559f7df2e56Smrg        length > (shmdesc->size - stuff->offset) / stuff->totalHeight) {
560f7df2e56Smrg        client->errorValue = stuff->totalWidth;
561f7df2e56Smrg        return BadValue;
56265b04b38Smrg    }
563f7df2e56Smrg    if (stuff->srcX > stuff->totalWidth) {
564f7df2e56Smrg        client->errorValue = stuff->srcX;
565f7df2e56Smrg        return BadValue;
56665b04b38Smrg    }
567f7df2e56Smrg    if (stuff->srcY > stuff->totalHeight) {
568f7df2e56Smrg        client->errorValue = stuff->srcY;
569f7df2e56Smrg        return BadValue;
57065b04b38Smrg    }
571f7df2e56Smrg    if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) {
572f7df2e56Smrg        client->errorValue = stuff->srcWidth;
573f7df2e56Smrg        return BadValue;
57465b04b38Smrg    }
575f7df2e56Smrg    if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) {
576f7df2e56Smrg        client->errorValue = stuff->srcHeight;
577f7df2e56Smrg        return BadValue;
57865b04b38Smrg    }
57905b261ecSmrg
58065b04b38Smrg    if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) ||
581f7df2e56Smrg         ((stuff->format != ZPixmap) &&
582f7df2e56Smrg          (stuff->srcX < screenInfo.bitmapScanlinePad) &&
583f7df2e56Smrg          ((stuff->format == XYBitmap) ||
584f7df2e56Smrg           ((stuff->srcY == 0) &&
585f7df2e56Smrg            (stuff->srcHeight == stuff->totalHeight))))) &&
586f7df2e56Smrg        ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth))
587f7df2e56Smrg        (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth,
588f7df2e56Smrg                               stuff->dstX, stuff->dstY,
589f7df2e56Smrg                               stuff->totalWidth, stuff->srcHeight,
590f7df2e56Smrg                               stuff->srcX, stuff->format,
591f7df2e56Smrg                               shmdesc->addr + stuff->offset +
592f7df2e56Smrg                               (stuff->srcY * length));
59365b04b38Smrg    else
594f7df2e56Smrg        doShmPutImage(pDraw, pGC, stuff->depth, stuff->format,
595f7df2e56Smrg                      stuff->totalWidth, stuff->totalHeight,
596f7df2e56Smrg                      stuff->srcX, stuff->srcY,
597f7df2e56Smrg                      stuff->srcWidth, stuff->srcHeight,
598f7df2e56Smrg                      stuff->dstX, stuff->dstY, shmdesc->addr + stuff->offset);
599f7df2e56Smrg
600f7df2e56Smrg    if (stuff->sendEvent) {
601f7df2e56Smrg        xShmCompletionEvent ev = {
602f7df2e56Smrg            .type = ShmCompletionCode,
603f7df2e56Smrg            .drawable = stuff->drawable,
604f7df2e56Smrg            .minorEvent = X_ShmPutImage,
605f7df2e56Smrg            .majorEvent = ShmReqCode,
606f7df2e56Smrg            .shmseg = stuff->shmseg,
607f7df2e56Smrg            .offset = stuff->offset
608f7df2e56Smrg        };
609f7df2e56Smrg        WriteEventsToClient(client, 1, (xEvent *) &ev);
61005b261ecSmrg    }
61165b04b38Smrg
61265b04b38Smrg    return Success;
61305b261ecSmrg}
61405b261ecSmrg
61565b04b38Smrgstatic int
61665b04b38SmrgProcShmGetImage(ClientPtr client)
61705b261ecSmrg{
618f7df2e56Smrg    DrawablePtr pDraw;
619f7df2e56Smrg    long lenPer = 0, length;
620f7df2e56Smrg    Mask plane = 0;
621f7df2e56Smrg    xShmGetImageReply xgi;
622f7df2e56Smrg    ShmDescPtr shmdesc;
623f7df2e56Smrg    VisualID visual = None;
624f7df2e56Smrg    RegionPtr pVisibleRegion = NULL;
625f7df2e56Smrg    int rc;
62605b261ecSmrg
62705b261ecSmrg    REQUEST(xShmGetImageReq);
62805b261ecSmrg
62905b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
630f7df2e56Smrg    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
631f7df2e56Smrg        client->errorValue = stuff->format;
6324202a189Smrg        return BadValue;
63305b261ecSmrg    }
634f7df2e56Smrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
63505b261ecSmrg    if (rc != Success)
636f7df2e56Smrg        return rc;
63705b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
638f7df2e56Smrg    if (pDraw->type == DRAWABLE_WINDOW) {
639f7df2e56Smrg        if (   /* check for being viewable */
640f7df2e56Smrg               !((WindowPtr) pDraw)->realized ||
641f7df2e56Smrg               /* check for being on screen */
642f7df2e56Smrg               pDraw->x + stuff->x < 0 ||
643f7df2e56Smrg               pDraw->x + stuff->x + (int) stuff->width > pDraw->pScreen->width
644f7df2e56Smrg               || pDraw->y + stuff->y < 0 ||
645f7df2e56Smrg               pDraw->y + stuff->y + (int) stuff->height >
646f7df2e56Smrg               pDraw->pScreen->height ||
647f7df2e56Smrg               /* check for being inside of border */
648f7df2e56Smrg               stuff->x < -wBorderWidth((WindowPtr) pDraw) ||
649f7df2e56Smrg               stuff->x + (int) stuff->width >
650f7df2e56Smrg               wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
651f7df2e56Smrg               stuff->y < -wBorderWidth((WindowPtr) pDraw) ||
652f7df2e56Smrg               stuff->y + (int) stuff->height >
653f7df2e56Smrg               wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
654f7df2e56Smrg            return BadMatch;
655f7df2e56Smrg        visual = wVisual(((WindowPtr) pDraw));
6567e31ba66Smrg        if (pDraw->type == DRAWABLE_WINDOW)
6577e31ba66Smrg            pVisibleRegion = &((WindowPtr) pDraw)->borderClip;
6584e185dc0Smrg        pDraw->pScreen->SourceValidate(pDraw, stuff->x, stuff->y,
6594e185dc0Smrg                                       stuff->width, stuff->height,
6604e185dc0Smrg                                       IncludeInferiors);
66165b04b38Smrg    }
662f7df2e56Smrg    else {
663f7df2e56Smrg        if (stuff->x < 0 ||
664f7df2e56Smrg            stuff->x + (int) stuff->width > pDraw->width ||
665f7df2e56Smrg            stuff->y < 0 || stuff->y + (int) stuff->height > pDraw->height)
666f7df2e56Smrg            return BadMatch;
667f7df2e56Smrg        visual = None;
66865b04b38Smrg    }
669f7df2e56Smrg    xgi = (xShmGetImageReply) {
670f7df2e56Smrg        .type = X_Reply,
671f7df2e56Smrg        .sequenceNumber = client->sequence,
672f7df2e56Smrg        .length = 0,
673f7df2e56Smrg        .visual = visual,
674f7df2e56Smrg        .depth = pDraw->depth
675f7df2e56Smrg    };
676f7df2e56Smrg    if (stuff->format == ZPixmap) {
677f7df2e56Smrg        length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height;
678f7df2e56Smrg    }
679f7df2e56Smrg    else {
680f7df2e56Smrg        lenPer = PixmapBytePad(stuff->width, 1) * stuff->height;
681f7df2e56Smrg        plane = ((Mask) 1) << (pDraw->depth - 1);
682f7df2e56Smrg        /* only planes asked for */
683f7df2e56Smrg        length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
68465b04b38Smrg    }
68565b04b38Smrg
68665b04b38Smrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
68765b04b38Smrg    xgi.size = length;
68865b04b38Smrg
689f7df2e56Smrg    if (length == 0) {
690f7df2e56Smrg        /* nothing to do */
69165b04b38Smrg    }
692f7df2e56Smrg    else if (stuff->format == ZPixmap) {
693f7df2e56Smrg        (*pDraw->pScreen->GetImage) (pDraw, stuff->x, stuff->y,
694f7df2e56Smrg                                     stuff->width, stuff->height,
695f7df2e56Smrg                                     stuff->format, stuff->planeMask,
696f7df2e56Smrg                                     shmdesc->addr + stuff->offset);
697f7df2e56Smrg        if (pVisibleRegion)
698f7df2e56Smrg            XaceCensorImage(client, pVisibleRegion,
699f7df2e56Smrg                    PixmapBytePad(stuff->width, pDraw->depth), pDraw,
700f7df2e56Smrg                    stuff->x, stuff->y, stuff->width, stuff->height,
701f7df2e56Smrg                    stuff->format, shmdesc->addr + stuff->offset);
70265b04b38Smrg    }
703f7df2e56Smrg    else {
70465b04b38Smrg
705f7df2e56Smrg        length = stuff->offset;
706f7df2e56Smrg        for (; plane; plane >>= 1) {
707f7df2e56Smrg            if (stuff->planeMask & plane) {
708f7df2e56Smrg                (*pDraw->pScreen->GetImage) (pDraw,
709f7df2e56Smrg                                             stuff->x, stuff->y,
710f7df2e56Smrg                                             stuff->width, stuff->height,
711f7df2e56Smrg                                             stuff->format, plane,
712f7df2e56Smrg                                             shmdesc->addr + length);
713f7df2e56Smrg                if (pVisibleRegion)
714f7df2e56Smrg                    XaceCensorImage(client, pVisibleRegion,
715f7df2e56Smrg                            BitmapBytePad(stuff->width), pDraw,
716f7df2e56Smrg                            stuff->x, stuff->y, stuff->width, stuff->height,
717f7df2e56Smrg                            stuff->format, shmdesc->addr + length);
718f7df2e56Smrg                length += lenPer;
719f7df2e56Smrg            }
720f7df2e56Smrg        }
72165b04b38Smrg    }
72265b04b38Smrg
72365b04b38Smrg    if (client->swapped) {
724f7df2e56Smrg        swaps(&xgi.sequenceNumber);
725f7df2e56Smrg        swapl(&xgi.length);
726f7df2e56Smrg        swapl(&xgi.visual);
727f7df2e56Smrg        swapl(&xgi.size);
72865b04b38Smrg    }
729f7df2e56Smrg    WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
73065b04b38Smrg
73165b04b38Smrg    return Success;
73265b04b38Smrg}
73365b04b38Smrg
73465b04b38Smrg#ifdef PANORAMIX
735f7df2e56Smrgstatic int
73665b04b38SmrgProcPanoramiXShmPutImage(ClientPtr client)
73765b04b38Smrg{
738f7df2e56Smrg    int j, result, orig_x, orig_y;
739f7df2e56Smrg    PanoramiXRes *draw, *gc;
740f7df2e56Smrg    Bool sendEvent, isRoot;
74165b04b38Smrg
74265b04b38Smrg    REQUEST(xShmPutImageReq);
74365b04b38Smrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
74465b04b38Smrg
745f7df2e56Smrg    result = dixLookupResourceByClass((void **) &draw, stuff->drawable,
746f7df2e56Smrg                                      XRC_DRAWABLE, client, DixWriteAccess);
74765b04b38Smrg    if (result != Success)
74865b04b38Smrg        return (result == BadValue) ? BadDrawable : result;
74965b04b38Smrg
750f7df2e56Smrg    result = dixLookupResourceByType((void **) &gc, stuff->gc,
751f7df2e56Smrg                                     XRT_GC, client, DixReadAccess);
75265b04b38Smrg    if (result != Success)
75365b04b38Smrg        return result;
75465b04b38Smrg
75565b04b38Smrg    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
75665b04b38Smrg
75765b04b38Smrg    orig_x = stuff->dstX;
75865b04b38Smrg    orig_y = stuff->dstY;
75965b04b38Smrg    sendEvent = stuff->sendEvent;
76065b04b38Smrg    stuff->sendEvent = 0;
76165b04b38Smrg    FOR_NSCREENS(j) {
762f7df2e56Smrg        if (!j)
763f7df2e56Smrg            stuff->sendEvent = sendEvent;
764f7df2e56Smrg        stuff->drawable = draw->info[j].id;
765f7df2e56Smrg        stuff->gc = gc->info[j].id;
766f7df2e56Smrg        if (isRoot) {
767f7df2e56Smrg            stuff->dstX = orig_x - screenInfo.screens[j]->x;
768f7df2e56Smrg            stuff->dstY = orig_y - screenInfo.screens[j]->y;
769f7df2e56Smrg        }
770f7df2e56Smrg        result = ProcShmPutImage(client);
771f7df2e56Smrg        if (result != Success)
772f7df2e56Smrg            break;
77365b04b38Smrg    }
77465b04b38Smrg    return result;
77565b04b38Smrg}
77665b04b38Smrg
777f7df2e56Smrgstatic int
77865b04b38SmrgProcPanoramiXShmGetImage(ClientPtr client)
77965b04b38Smrg{
780f7df2e56Smrg    PanoramiXRes *draw;
781f7df2e56Smrg    DrawablePtr *drawables;
782f7df2e56Smrg    DrawablePtr pDraw;
783f7df2e56Smrg    xShmGetImageReply xgi;
784f7df2e56Smrg    ShmDescPtr shmdesc;
785f7df2e56Smrg    int i, x, y, w, h, format, rc;
786f7df2e56Smrg    Mask plane = 0, planemask;
787f7df2e56Smrg    long lenPer = 0, length, widthBytesLine;
788f7df2e56Smrg    Bool isRoot;
78965b04b38Smrg
79065b04b38Smrg    REQUEST(xShmGetImageReq);
79165b04b38Smrg
79265b04b38Smrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
79365b04b38Smrg
79465b04b38Smrg    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
795f7df2e56Smrg        client->errorValue = stuff->format;
79665b04b38Smrg        return BadValue;
79765b04b38Smrg    }
79865b04b38Smrg
799f7df2e56Smrg    rc = dixLookupResourceByClass((void **) &draw, stuff->drawable,
800f7df2e56Smrg                                  XRC_DRAWABLE, client, DixWriteAccess);
80165b04b38Smrg    if (rc != Success)
802f7df2e56Smrg        return (rc == BadValue) ? BadDrawable : rc;
80365b04b38Smrg
80465b04b38Smrg    if (draw->type == XRT_PIXMAP)
805f7df2e56Smrg        return ProcShmGetImage(client);
80665b04b38Smrg
807f7df2e56Smrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
80865b04b38Smrg    if (rc != Success)
809f7df2e56Smrg        return rc;
81065b04b38Smrg
81165b04b38Smrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
81265b04b38Smrg
81365b04b38Smrg    x = stuff->x;
81465b04b38Smrg    y = stuff->y;
81565b04b38Smrg    w = stuff->width;
81665b04b38Smrg    h = stuff->height;
81765b04b38Smrg    format = stuff->format;
81865b04b38Smrg    planemask = stuff->planeMask;
81965b04b38Smrg
82065b04b38Smrg    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
82165b04b38Smrg
822f7df2e56Smrg    if (isRoot) {
823f7df2e56Smrg        if (                    /* check for being onscreen */
824f7df2e56Smrg               x < 0 || x + w > PanoramiXPixWidth ||
825f7df2e56Smrg               y < 0 || y + h > PanoramiXPixHeight)
826f7df2e56Smrg            return BadMatch;
827f7df2e56Smrg    }
828f7df2e56Smrg    else {
829f7df2e56Smrg        if (                    /* check for being onscreen */
830f7df2e56Smrg               screenInfo.screens[0]->x + pDraw->x + x < 0 ||
831f7df2e56Smrg               screenInfo.screens[0]->x + pDraw->x + x + w > PanoramiXPixWidth
832f7df2e56Smrg               || screenInfo.screens[0]->y + pDraw->y + y < 0 ||
833f7df2e56Smrg               screenInfo.screens[0]->y + pDraw->y + y + h > PanoramiXPixHeight
834f7df2e56Smrg               ||
835f7df2e56Smrg               /* check for being inside of border */
836f7df2e56Smrg               x < -wBorderWidth((WindowPtr) pDraw) ||
837f7df2e56Smrg               x + w > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
838f7df2e56Smrg               y < -wBorderWidth((WindowPtr) pDraw) ||
839f7df2e56Smrg               y + h > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
840f7df2e56Smrg            return BadMatch;
84165b04b38Smrg    }
84265b04b38Smrg
8437e31ba66Smrg    if (format == ZPixmap) {
8447e31ba66Smrg        widthBytesLine = PixmapBytePad(w, pDraw->depth);
8457e31ba66Smrg        length = widthBytesLine * h;
8467e31ba66Smrg    }
8477e31ba66Smrg    else {
8487e31ba66Smrg        widthBytesLine = PixmapBytePad(w, 1);
8497e31ba66Smrg        lenPer = widthBytesLine * h;
8507e31ba66Smrg        plane = ((Mask) 1) << (pDraw->depth - 1);
8517e31ba66Smrg        length = lenPer * Ones(planemask & (plane | (plane - 1)));
8527e31ba66Smrg    }
8537e31ba66Smrg
8547e31ba66Smrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
8557e31ba66Smrg
8564202a189Smrg    drawables = calloc(PanoramiXNumScreens, sizeof(DrawablePtr));
857f7df2e56Smrg    if (!drawables)
858f7df2e56Smrg        return BadAlloc;
8594202a189Smrg
86005b261ecSmrg    drawables[0] = pDraw;
861f7df2e56Smrg    FOR_NSCREENS_FORWARD_SKIP(i) {
862f7df2e56Smrg        rc = dixLookupDrawable(drawables + i, draw->info[i].id, client, 0,
863f7df2e56Smrg                               DixReadAccess);
864f7df2e56Smrg        if (rc != Success) {
865f7df2e56Smrg            free(drawables);
866f7df2e56Smrg            return rc;
867f7df2e56Smrg        }
86805b261ecSmrg    }
8694e185dc0Smrg    FOR_NSCREENS_FORWARD(i) {
8704e185dc0Smrg        drawables[i]->pScreen->SourceValidate(drawables[i], 0, 0,
8714e185dc0Smrg                                              drawables[i]->width,
8724e185dc0Smrg                                              drawables[i]->height,
8734e185dc0Smrg                                              IncludeInferiors);
8744e185dc0Smrg    }
87505b261ecSmrg
876f7df2e56Smrg    xgi = (xShmGetImageReply) {
877f7df2e56Smrg        .type = X_Reply,
878f7df2e56Smrg        .sequenceNumber = client->sequence,
879f7df2e56Smrg        .length = 0,
880f7df2e56Smrg        .visual = wVisual(((WindowPtr) pDraw)),
881f7df2e56Smrg        .depth = pDraw->depth
882f7df2e56Smrg    };
883f7df2e56Smrg
88405b261ecSmrg    xgi.size = length;
88505b261ecSmrg
886f7df2e56Smrg    if (length == 0) {          /* nothing to do */
887f7df2e56Smrg    }
88805b261ecSmrg    else if (format == ZPixmap) {
889f7df2e56Smrg        XineramaGetImageData(drawables, x, y, w, h, format, planemask,
890f7df2e56Smrg                             shmdesc->addr + stuff->offset,
891f7df2e56Smrg                             widthBytesLine, isRoot);
892f7df2e56Smrg    }
893f7df2e56Smrg    else {
89405b261ecSmrg
895f7df2e56Smrg        length = stuff->offset;
89605b261ecSmrg        for (; plane; plane >>= 1) {
897f7df2e56Smrg            if (planemask & plane) {
898f7df2e56Smrg                XineramaGetImageData(drawables, x, y, w, h,
899f7df2e56Smrg                                     format, plane, shmdesc->addr + length,
900f7df2e56Smrg                                     widthBytesLine, isRoot);
901f7df2e56Smrg                length += lenPer;
902f7df2e56Smrg            }
903f7df2e56Smrg        }
90405b261ecSmrg    }
9054202a189Smrg    free(drawables);
906f7df2e56Smrg
90705b261ecSmrg    if (client->swapped) {
908f7df2e56Smrg        swaps(&xgi.sequenceNumber);
909f7df2e56Smrg        swapl(&xgi.length);
910f7df2e56Smrg        swapl(&xgi.visual);
911f7df2e56Smrg        swapl(&xgi.size);
91205b261ecSmrg    }
913f7df2e56Smrg    WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
91405b261ecSmrg
9154202a189Smrg    return Success;
91605b261ecSmrg}
91705b261ecSmrg
91805b261ecSmrgstatic int
9194642e01fSmrgProcPanoramiXShmCreatePixmap(ClientPtr client)
92005b261ecSmrg{
92105b261ecSmrg    ScreenPtr pScreen = NULL;
92205b261ecSmrg    PixmapPtr pMap = NULL;
92305b261ecSmrg    DrawablePtr pDraw;
92405b261ecSmrg    DepthPtr pDepth;
92505b261ecSmrg    int i, j, result, rc;
92605b261ecSmrg    ShmDescPtr shmdesc;
927f7df2e56Smrg
92805b261ecSmrg    REQUEST(xShmCreatePixmapReq);
92905b261ecSmrg    unsigned int width, height, depth;
93005b261ecSmrg    unsigned long size;
93105b261ecSmrg    PanoramiXRes *newPix;
93205b261ecSmrg
93305b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
93405b261ecSmrg    client->errorValue = stuff->pid;
93505b261ecSmrg    if (!sharedPixmaps)
936f7df2e56Smrg        return BadImplementation;
93705b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->pid, client);
93805b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
939f7df2e56Smrg                           DixGetAttrAccess);
94005b261ecSmrg    if (rc != Success)
941f7df2e56Smrg        return rc;
94205b261ecSmrg
94305b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
94405b261ecSmrg
94505b261ecSmrg    width = stuff->width;
94605b261ecSmrg    height = stuff->height;
94705b261ecSmrg    depth = stuff->depth;
948f7df2e56Smrg    if (!width || !height || !depth) {
949f7df2e56Smrg        client->errorValue = 0;
95005b261ecSmrg        return BadValue;
95105b261ecSmrg    }
95205b261ecSmrg    if (width > 32767 || height > 32767)
95305b261ecSmrg        return BadAlloc;
95405b261ecSmrg
955f7df2e56Smrg    if (stuff->depth != 1) {
95605b261ecSmrg        pDepth = pDraw->pScreen->allowedDepths;
957f7df2e56Smrg        for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
958f7df2e56Smrg            if (pDepth->depth == stuff->depth)
959f7df2e56Smrg                goto CreatePmap;
960f7df2e56Smrg        client->errorValue = stuff->depth;
96105b261ecSmrg        return BadValue;
96205b261ecSmrg    }
96305b261ecSmrg
964f7df2e56Smrg CreatePmap:
96505b261ecSmrg    size = PixmapBytePad(width, depth) * height;
96605b261ecSmrg    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
96705b261ecSmrg        if (size < width * height)
96805b261ecSmrg            return BadAlloc;
96905b261ecSmrg    }
97005b261ecSmrg    /* thankfully, offset is unsigned */
97105b261ecSmrg    if (stuff->offset + size < size)
972f7df2e56Smrg        return BadAlloc;
97305b261ecSmrg
97405b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
97505b261ecSmrg
976f7df2e56Smrg    if (!(newPix = malloc(sizeof(PanoramiXRes))))
977f7df2e56Smrg        return BadAlloc;
97805b261ecSmrg
97905b261ecSmrg    newPix->type = XRT_PIXMAP;
98005b261ecSmrg    newPix->u.pix.shared = TRUE;
981f7df2e56Smrg    panoramix_setup_ids(newPix, client, stuff->pid);
98205b261ecSmrg
9834202a189Smrg    result = Success;
98405b261ecSmrg
98505b261ecSmrg    FOR_NSCREENS(j) {
986f7df2e56Smrg        ShmScrPrivateRec *screen_priv;
987f7df2e56Smrg
988f7df2e56Smrg        pScreen = screenInfo.screens[j];
989f7df2e56Smrg
990f7df2e56Smrg        screen_priv = ShmGetScreenPriv(pScreen);
991f7df2e56Smrg        pMap = (*screen_priv->shmFuncs->CreatePixmap) (pScreen,
992f7df2e56Smrg                                                       stuff->width,
993f7df2e56Smrg                                                       stuff->height,
994f7df2e56Smrg                                                       stuff->depth,
995f7df2e56Smrg                                                       shmdesc->addr +
996f7df2e56Smrg                                                       stuff->offset);
997f7df2e56Smrg
998f7df2e56Smrg        if (pMap) {
999f7df2e56Smrg            result = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid,
1000f7df2e56Smrg                              RT_PIXMAP, pMap, RT_NONE, NULL, DixCreateAccess);
1001f7df2e56Smrg            if (result != Success) {
1002f7df2e56Smrg                pDraw->pScreen->DestroyPixmap(pMap);
10037e31ba66Smrg                break;
1004f7df2e56Smrg            }
1005f7df2e56Smrg            dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
100605b261ecSmrg            shmdesc->refcnt++;
1007f7df2e56Smrg            pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1008f7df2e56Smrg            pMap->drawable.id = newPix->info[j].id;
1009f7df2e56Smrg            if (!AddResource(newPix->info[j].id, RT_PIXMAP, (void *) pMap)) {
1010f7df2e56Smrg                result = BadAlloc;
1011f7df2e56Smrg                break;
1012f7df2e56Smrg            }
1013f7df2e56Smrg        }
1014f7df2e56Smrg        else {
1015f7df2e56Smrg            result = BadAlloc;
1016f7df2e56Smrg            break;
1017f7df2e56Smrg        }
101805b261ecSmrg    }
101905b261ecSmrg
10207e31ba66Smrg    if (result != Success) {
1021f7df2e56Smrg        while (j--)
1022f7df2e56Smrg            FreeResource(newPix->info[j].id, RT_NONE);
1023f7df2e56Smrg        free(newPix);
1024f7df2e56Smrg    }
1025f7df2e56Smrg    else
1026f7df2e56Smrg        AddResource(stuff->pid, XRT_PIXMAP, newPix);
102705b261ecSmrg
102805b261ecSmrg    return result;
102905b261ecSmrg}
103005b261ecSmrg#endif
103105b261ecSmrg
103205b261ecSmrgstatic PixmapPtr
1033f7df2e56SmrgfbShmCreatePixmap(ScreenPtr pScreen,
1034f7df2e56Smrg                  int width, int height, int depth, char *addr)
103505b261ecSmrg{
10364642e01fSmrg    PixmapPtr pPixmap;
103705b261ecSmrg
1038f7df2e56Smrg    pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0);
103905b261ecSmrg    if (!pPixmap)
1040f7df2e56Smrg        return NullPixmap;
1041f7df2e56Smrg
1042f7df2e56Smrg    if (!(*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth,
1043f7df2e56Smrg                                         BitsPerPixel(depth),
1044f7df2e56Smrg                                         PixmapBytePad(width, depth),
1045f7df2e56Smrg                                         (void *) addr)) {
1046f7df2e56Smrg        (*pScreen->DestroyPixmap) (pPixmap);
1047f7df2e56Smrg        return NullPixmap;
104805b261ecSmrg    }
104905b261ecSmrg    return pPixmap;
105005b261ecSmrg}
105105b261ecSmrg
105205b261ecSmrgstatic int
10534642e01fSmrgProcShmCreatePixmap(ClientPtr client)
105405b261ecSmrg{
105505b261ecSmrg    PixmapPtr pMap;
105605b261ecSmrg    DrawablePtr pDraw;
105705b261ecSmrg    DepthPtr pDepth;
10584642e01fSmrg    int i, rc;
105905b261ecSmrg    ShmDescPtr shmdesc;
10604202a189Smrg    ShmScrPrivateRec *screen_priv;
1061f7df2e56Smrg
106205b261ecSmrg    REQUEST(xShmCreatePixmapReq);
106305b261ecSmrg    unsigned int width, height, depth;
106405b261ecSmrg    unsigned long size;
106505b261ecSmrg
106605b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
106705b261ecSmrg    client->errorValue = stuff->pid;
106805b261ecSmrg    if (!sharedPixmaps)
1069f7df2e56Smrg        return BadImplementation;
107005b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->pid, client);
107105b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
1072f7df2e56Smrg                           DixGetAttrAccess);
107305b261ecSmrg    if (rc != Success)
1074f7df2e56Smrg        return rc;
107505b261ecSmrg
107605b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
1077f7df2e56Smrg
107805b261ecSmrg    width = stuff->width;
107905b261ecSmrg    height = stuff->height;
108005b261ecSmrg    depth = stuff->depth;
1081f7df2e56Smrg    if (!width || !height || !depth) {
1082f7df2e56Smrg        client->errorValue = 0;
108305b261ecSmrg        return BadValue;
108405b261ecSmrg    }
108505b261ecSmrg    if (width > 32767 || height > 32767)
1086f7df2e56Smrg        return BadAlloc;
108705b261ecSmrg
1088f7df2e56Smrg    if (stuff->depth != 1) {
108905b261ecSmrg        pDepth = pDraw->pScreen->allowedDepths;
1090f7df2e56Smrg        for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
1091f7df2e56Smrg            if (pDepth->depth == stuff->depth)
1092f7df2e56Smrg                goto CreatePmap;
1093f7df2e56Smrg        client->errorValue = stuff->depth;
109405b261ecSmrg        return BadValue;
109505b261ecSmrg    }
109605b261ecSmrg
1097f7df2e56Smrg CreatePmap:
109805b261ecSmrg    size = PixmapBytePad(width, depth) * height;
109905b261ecSmrg    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
1100f7df2e56Smrg        if (size < width * height)
1101f7df2e56Smrg            return BadAlloc;
110205b261ecSmrg    }
110305b261ecSmrg    /* thankfully, offset is unsigned */
110405b261ecSmrg    if (stuff->offset + size < size)
1105f7df2e56Smrg        return BadAlloc;
110605b261ecSmrg
110705b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
11084202a189Smrg    screen_priv = ShmGetScreenPriv(pDraw->pScreen);
1109f7df2e56Smrg    pMap = (*screen_priv->shmFuncs->CreatePixmap) (pDraw->pScreen, stuff->width,
1110f7df2e56Smrg                                                   stuff->height, stuff->depth,
1111f7df2e56Smrg                                                   shmdesc->addr +
1112f7df2e56Smrg                                                   stuff->offset);
1113f7df2e56Smrg    if (pMap) {
1114f7df2e56Smrg        rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP,
1115f7df2e56Smrg                      pMap, RT_NONE, NULL, DixCreateAccess);
1116f7df2e56Smrg        if (rc != Success) {
1117f7df2e56Smrg            pDraw->pScreen->DestroyPixmap(pMap);
1118f7df2e56Smrg            return rc;
1119f7df2e56Smrg        }
1120f7df2e56Smrg        dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
1121f7df2e56Smrg        shmdesc->refcnt++;
1122f7df2e56Smrg        pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1123f7df2e56Smrg        pMap->drawable.id = stuff->pid;
1124f7df2e56Smrg        if (AddResource(stuff->pid, RT_PIXMAP, (void *) pMap)) {
1125f7df2e56Smrg            return Success;
1126f7df2e56Smrg        }
1127f7df2e56Smrg    }
1128f7df2e56Smrg    return BadAlloc;
1129f7df2e56Smrg}
1130f7df2e56Smrg
1131f7df2e56Smrg#ifdef SHM_FD_PASSING
1132f7df2e56Smrg
1133f7df2e56Smrgstatic void
1134f7df2e56SmrgShmBusfaultNotify(void *context)
1135f7df2e56Smrg{
1136f7df2e56Smrg    ShmDescPtr shmdesc = context;
1137f7df2e56Smrg
1138f7df2e56Smrg    ErrorF("shared memory 0x%x truncated by client\n",
1139f7df2e56Smrg           (unsigned int) shmdesc->resource);
1140f7df2e56Smrg    busfault_unregister(shmdesc->busfault);
1141f7df2e56Smrg    shmdesc->busfault = NULL;
1142f7df2e56Smrg    FreeResource (shmdesc->resource, RT_NONE);
1143f7df2e56Smrg}
1144f7df2e56Smrg
1145f7df2e56Smrgstatic int
1146f7df2e56SmrgProcShmAttachFd(ClientPtr client)
1147f7df2e56Smrg{
1148f7df2e56Smrg    int fd;
1149f7df2e56Smrg    ShmDescPtr shmdesc;
1150f7df2e56Smrg    REQUEST(xShmAttachFdReq);
1151f7df2e56Smrg    struct stat statb;
1152f7df2e56Smrg
1153f7df2e56Smrg    SetReqFds(client, 1);
1154f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmAttachFdReq);
1155f7df2e56Smrg    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
1156f7df2e56Smrg    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1157f7df2e56Smrg        client->errorValue = stuff->readOnly;
1158f7df2e56Smrg        return BadValue;
1159f7df2e56Smrg    }
1160f7df2e56Smrg    fd = ReadFdFromClient(client);
1161f7df2e56Smrg    if (fd < 0)
1162f7df2e56Smrg        return BadMatch;
1163f7df2e56Smrg
1164f7df2e56Smrg    if (fstat(fd, &statb) < 0 || statb.st_size == 0) {
1165f7df2e56Smrg        close(fd);
1166f7df2e56Smrg        return BadMatch;
1167f7df2e56Smrg    }
1168f7df2e56Smrg
1169f7df2e56Smrg    shmdesc = malloc(sizeof(ShmDescRec));
1170f7df2e56Smrg    if (!shmdesc) {
1171f7df2e56Smrg        close(fd);
1172f7df2e56Smrg        return BadAlloc;
1173f7df2e56Smrg    }
1174f7df2e56Smrg    shmdesc->is_fd = TRUE;
1175f7df2e56Smrg    shmdesc->addr = mmap(NULL, statb.st_size,
1176f7df2e56Smrg                         stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1177f7df2e56Smrg                         MAP_SHARED,
1178f7df2e56Smrg                         fd, 0);
1179f7df2e56Smrg
1180f7df2e56Smrg    close(fd);
1181f7df2e56Smrg    if (shmdesc->addr == ((char *) -1)) {
1182f7df2e56Smrg        free(shmdesc);
1183f7df2e56Smrg        return BadAccess;
1184f7df2e56Smrg    }
1185f7df2e56Smrg
1186f7df2e56Smrg    shmdesc->refcnt = 1;
1187f7df2e56Smrg    shmdesc->writable = !stuff->readOnly;
1188f7df2e56Smrg    shmdesc->size = statb.st_size;
1189f7df2e56Smrg    shmdesc->resource = stuff->shmseg;
1190f7df2e56Smrg
1191f7df2e56Smrg    shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1192f7df2e56Smrg    if (!shmdesc->busfault) {
1193f7df2e56Smrg        munmap(shmdesc->addr, shmdesc->size);
1194f7df2e56Smrg        free(shmdesc);
1195f7df2e56Smrg        return BadAlloc;
1196f7df2e56Smrg    }
1197f7df2e56Smrg
1198f7df2e56Smrg    shmdesc->next = Shmsegs;
1199f7df2e56Smrg    Shmsegs = shmdesc;
1200f7df2e56Smrg
1201f7df2e56Smrg    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
1202f7df2e56Smrg        return BadAlloc;
1203f7df2e56Smrg    return Success;
1204f7df2e56Smrg}
1205f7df2e56Smrg
1206f7df2e56Smrgstatic int
1207f7df2e56Smrgshm_tmpfile(void)
1208f7df2e56Smrg{
12094e185dc0Smrg    const char *shmdirs[] = {
12104e185dc0Smrg        "/run/shm",
12114e185dc0Smrg        "/var/tmp",
12124e185dc0Smrg        "/tmp",
12134e185dc0Smrg    };
12144e185dc0Smrg    int	fd;
12154e185dc0Smrg
12164e185dc0Smrg#ifdef HAVE_MEMFD_CREATE
12174e185dc0Smrg    fd = memfd_create("xorg", MFD_CLOEXEC|MFD_ALLOW_SEALING);
12184e185dc0Smrg    if (fd != -1) {
12194e185dc0Smrg        fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
12204e185dc0Smrg        DebugF ("Using memfd_create\n");
12214e185dc0Smrg        return fd;
12224e185dc0Smrg    }
12234e185dc0Smrg#endif
12244e185dc0Smrg
1225f7df2e56Smrg#ifdef O_TMPFILE
12264e185dc0Smrg    for (int i = 0; i < ARRAY_SIZE(shmdirs); i++) {
12274e185dc0Smrg        fd = open(shmdirs[i], O_TMPFILE|O_RDWR|O_CLOEXEC|O_EXCL, 0666);
12284e185dc0Smrg        if (fd >= 0) {
12294e185dc0Smrg            DebugF ("Using O_TMPFILE\n");
12304e185dc0Smrg            return fd;
12314e185dc0Smrg        }
12324e185dc0Smrg    }
12334e185dc0Smrg    ErrorF ("Not using O_TMPFILE\n");
1234f7df2e56Smrg#endif
12354e185dc0Smrg
12364e185dc0Smrg    for (int i = 0; i < ARRAY_SIZE(shmdirs); i++) {
12374e185dc0Smrg        char template[PATH_MAX];
12384e185dc0Smrg        snprintf(template, ARRAY_SIZE(template), "%s/shmfd-XXXXXX", shmdirs[i]);
12397e31ba66Smrg#ifdef HAVE_MKOSTEMP
12404e185dc0Smrg        fd = mkostemp(template, O_CLOEXEC);
12417e31ba66Smrg#else
12424e185dc0Smrg        fd = mkstemp(template);
12437e31ba66Smrg#endif
12444e185dc0Smrg        if (fd < 0)
12454e185dc0Smrg            continue;
12464e185dc0Smrg        unlink(template);
12477e31ba66Smrg#ifndef HAVE_MKOSTEMP
12484e185dc0Smrg        int flags = fcntl(fd, F_GETFD);
12494e185dc0Smrg        if (flags != -1) {
12504e185dc0Smrg            flags |= FD_CLOEXEC;
12515a112b11Smrg            (void) fcntl(fd, F_SETFD, flags);
12524e185dc0Smrg        }
1253f7df2e56Smrg#endif
12544e185dc0Smrg        return fd;
12554e185dc0Smrg    }
12564e185dc0Smrg
12574e185dc0Smrg    return -1;
1258f7df2e56Smrg}
1259f7df2e56Smrg
1260f7df2e56Smrgstatic int
1261f7df2e56SmrgProcShmCreateSegment(ClientPtr client)
1262f7df2e56Smrg{
1263f7df2e56Smrg    int fd;
1264f7df2e56Smrg    ShmDescPtr shmdesc;
1265f7df2e56Smrg    REQUEST(xShmCreateSegmentReq);
1266f7df2e56Smrg    xShmCreateSegmentReply rep = {
1267f7df2e56Smrg        .type = X_Reply,
1268f7df2e56Smrg        .nfd = 1,
1269f7df2e56Smrg        .sequenceNumber = client->sequence,
1270f7df2e56Smrg        .length = 0,
1271f7df2e56Smrg    };
1272f7df2e56Smrg
1273f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
12747e31ba66Smrg    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
1275f7df2e56Smrg    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1276f7df2e56Smrg        client->errorValue = stuff->readOnly;
1277f7df2e56Smrg        return BadValue;
127805b261ecSmrg    }
1279f7df2e56Smrg    fd = shm_tmpfile();
1280f7df2e56Smrg    if (fd < 0)
1281f7df2e56Smrg        return BadAlloc;
1282f7df2e56Smrg    if (ftruncate(fd, stuff->size) < 0) {
1283f7df2e56Smrg        close(fd);
1284f7df2e56Smrg        return BadAlloc;
1285f7df2e56Smrg    }
1286f7df2e56Smrg    shmdesc = malloc(sizeof(ShmDescRec));
1287f7df2e56Smrg    if (!shmdesc) {
1288f7df2e56Smrg        close(fd);
1289f7df2e56Smrg        return BadAlloc;
1290f7df2e56Smrg    }
1291f7df2e56Smrg    shmdesc->is_fd = TRUE;
1292f7df2e56Smrg    shmdesc->addr = mmap(NULL, stuff->size,
1293f7df2e56Smrg                         stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1294f7df2e56Smrg                         MAP_SHARED,
1295f7df2e56Smrg                         fd, 0);
1296f7df2e56Smrg
1297f7df2e56Smrg    if (shmdesc->addr == ((char *) -1)) {
1298f7df2e56Smrg        close(fd);
1299f7df2e56Smrg        free(shmdesc);
1300f7df2e56Smrg        return BadAccess;
1301f7df2e56Smrg    }
1302f7df2e56Smrg
1303f7df2e56Smrg    shmdesc->refcnt = 1;
1304f7df2e56Smrg    shmdesc->writable = !stuff->readOnly;
1305f7df2e56Smrg    shmdesc->size = stuff->size;
1306f7df2e56Smrg
1307f7df2e56Smrg    shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1308f7df2e56Smrg    if (!shmdesc->busfault) {
1309f7df2e56Smrg        close(fd);
1310f7df2e56Smrg        munmap(shmdesc->addr, shmdesc->size);
1311f7df2e56Smrg        free(shmdesc);
1312f7df2e56Smrg        return BadAlloc;
1313f7df2e56Smrg    }
1314f7df2e56Smrg
1315f7df2e56Smrg    shmdesc->next = Shmsegs;
1316f7df2e56Smrg    Shmsegs = shmdesc;
1317f7df2e56Smrg
1318f7df2e56Smrg    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc)) {
1319f7df2e56Smrg        close(fd);
1320f7df2e56Smrg        return BadAlloc;
1321f7df2e56Smrg    }
1322f7df2e56Smrg
1323f7df2e56Smrg    if (WriteFdToClient(client, fd, TRUE) < 0) {
1324f7df2e56Smrg        FreeResource(stuff->shmseg, RT_NONE);
1325f7df2e56Smrg        close(fd);
1326f7df2e56Smrg        return BadAlloc;
1327f7df2e56Smrg    }
1328f7df2e56Smrg    WriteToClient(client, sizeof (xShmCreateSegmentReply), &rep);
1329f7df2e56Smrg    return Success;
133005b261ecSmrg}
1331f7df2e56Smrg#endif /* SHM_FD_PASSING */
133205b261ecSmrg
133305b261ecSmrgstatic int
1334f7df2e56SmrgProcShmDispatch(ClientPtr client)
133505b261ecSmrg{
133605b261ecSmrg    REQUEST(xReq);
13377e31ba66Smrg
13387e31ba66Smrg    if (stuff->data == X_ShmQueryVersion)
1339f7df2e56Smrg        return ProcShmQueryVersion(client);
13407e31ba66Smrg
13417e31ba66Smrg    if (!client->local)
13427e31ba66Smrg        return BadRequest;
13437e31ba66Smrg
13447e31ba66Smrg    switch (stuff->data) {
134505b261ecSmrg    case X_ShmAttach:
1346f7df2e56Smrg        return ProcShmAttach(client);
134705b261ecSmrg    case X_ShmDetach:
1348f7df2e56Smrg        return ProcShmDetach(client);
134905b261ecSmrg    case X_ShmPutImage:
135005b261ecSmrg#ifdef PANORAMIX
1351f7df2e56Smrg        if (!noPanoramiXExtension)
1352f7df2e56Smrg            return ProcPanoramiXShmPutImage(client);
135305b261ecSmrg#endif
1354f7df2e56Smrg        return ProcShmPutImage(client);
135505b261ecSmrg    case X_ShmGetImage:
135605b261ecSmrg#ifdef PANORAMIX
1357f7df2e56Smrg        if (!noPanoramiXExtension)
1358f7df2e56Smrg            return ProcPanoramiXShmGetImage(client);
135905b261ecSmrg#endif
1360f7df2e56Smrg        return ProcShmGetImage(client);
136105b261ecSmrg    case X_ShmCreatePixmap:
136205b261ecSmrg#ifdef PANORAMIX
1363f7df2e56Smrg        if (!noPanoramiXExtension)
1364f7df2e56Smrg            return ProcPanoramiXShmCreatePixmap(client);
1365f7df2e56Smrg#endif
1366f7df2e56Smrg        return ProcShmCreatePixmap(client);
1367f7df2e56Smrg#ifdef SHM_FD_PASSING
1368f7df2e56Smrg    case X_ShmAttachFd:
1369f7df2e56Smrg        return ProcShmAttachFd(client);
1370f7df2e56Smrg    case X_ShmCreateSegment:
1371f7df2e56Smrg        return ProcShmCreateSegment(client);
137205b261ecSmrg#endif
137305b261ecSmrg    default:
1374f7df2e56Smrg        return BadRequest;
137505b261ecSmrg    }
137605b261ecSmrg}
137705b261ecSmrg
13787e31ba66Smrgstatic void _X_COLD
1379f7df2e56SmrgSShmCompletionEvent(xShmCompletionEvent * from, xShmCompletionEvent * to)
138005b261ecSmrg{
138105b261ecSmrg    to->type = from->type;
138205b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
138305b261ecSmrg    cpswapl(from->drawable, to->drawable);
138405b261ecSmrg    cpswaps(from->minorEvent, to->minorEvent);
138505b261ecSmrg    to->majorEvent = from->majorEvent;
138605b261ecSmrg    cpswapl(from->shmseg, to->shmseg);
138705b261ecSmrg    cpswapl(from->offset, to->offset);
138805b261ecSmrg}
138905b261ecSmrg
13907e31ba66Smrgstatic int _X_COLD
13914642e01fSmrgSProcShmQueryVersion(ClientPtr client)
139205b261ecSmrg{
139305b261ecSmrg    REQUEST(xShmQueryVersionReq);
139405b261ecSmrg
1395f7df2e56Smrg    swaps(&stuff->length);
139605b261ecSmrg    return ProcShmQueryVersion(client);
139705b261ecSmrg}
139805b261ecSmrg
13997e31ba66Smrgstatic int _X_COLD
14004642e01fSmrgSProcShmAttach(ClientPtr client)
140105b261ecSmrg{
140205b261ecSmrg    REQUEST(xShmAttachReq);
1403f7df2e56Smrg    swaps(&stuff->length);
140405b261ecSmrg    REQUEST_SIZE_MATCH(xShmAttachReq);
1405f7df2e56Smrg    swapl(&stuff->shmseg);
1406f7df2e56Smrg    swapl(&stuff->shmid);
140705b261ecSmrg    return ProcShmAttach(client);
140805b261ecSmrg}
140905b261ecSmrg
14107e31ba66Smrgstatic int _X_COLD
14114642e01fSmrgSProcShmDetach(ClientPtr client)
141205b261ecSmrg{
141305b261ecSmrg    REQUEST(xShmDetachReq);
1414f7df2e56Smrg    swaps(&stuff->length);
141505b261ecSmrg    REQUEST_SIZE_MATCH(xShmDetachReq);
1416f7df2e56Smrg    swapl(&stuff->shmseg);
141705b261ecSmrg    return ProcShmDetach(client);
141805b261ecSmrg}
141905b261ecSmrg
14207e31ba66Smrgstatic int _X_COLD
14214642e01fSmrgSProcShmPutImage(ClientPtr client)
142205b261ecSmrg{
142305b261ecSmrg    REQUEST(xShmPutImageReq);
1424f7df2e56Smrg    swaps(&stuff->length);
142505b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
1426f7df2e56Smrg    swapl(&stuff->drawable);
1427f7df2e56Smrg    swapl(&stuff->gc);
1428f7df2e56Smrg    swaps(&stuff->totalWidth);
1429f7df2e56Smrg    swaps(&stuff->totalHeight);
1430f7df2e56Smrg    swaps(&stuff->srcX);
1431f7df2e56Smrg    swaps(&stuff->srcY);
1432f7df2e56Smrg    swaps(&stuff->srcWidth);
1433f7df2e56Smrg    swaps(&stuff->srcHeight);
1434f7df2e56Smrg    swaps(&stuff->dstX);
1435f7df2e56Smrg    swaps(&stuff->dstY);
1436f7df2e56Smrg    swapl(&stuff->shmseg);
1437f7df2e56Smrg    swapl(&stuff->offset);
143805b261ecSmrg    return ProcShmPutImage(client);
143905b261ecSmrg}
144005b261ecSmrg
14417e31ba66Smrgstatic int _X_COLD
14424642e01fSmrgSProcShmGetImage(ClientPtr client)
144305b261ecSmrg{
144405b261ecSmrg    REQUEST(xShmGetImageReq);
1445f7df2e56Smrg    swaps(&stuff->length);
144605b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
1447f7df2e56Smrg    swapl(&stuff->drawable);
1448f7df2e56Smrg    swaps(&stuff->x);
1449f7df2e56Smrg    swaps(&stuff->y);
1450f7df2e56Smrg    swaps(&stuff->width);
1451f7df2e56Smrg    swaps(&stuff->height);
1452f7df2e56Smrg    swapl(&stuff->planeMask);
1453f7df2e56Smrg    swapl(&stuff->shmseg);
1454f7df2e56Smrg    swapl(&stuff->offset);
145505b261ecSmrg    return ProcShmGetImage(client);
145605b261ecSmrg}
145705b261ecSmrg
14587e31ba66Smrgstatic int _X_COLD
14594642e01fSmrgSProcShmCreatePixmap(ClientPtr client)
146005b261ecSmrg{
146105b261ecSmrg    REQUEST(xShmCreatePixmapReq);
1462f7df2e56Smrg    swaps(&stuff->length);
146305b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1464f7df2e56Smrg    swapl(&stuff->pid);
1465f7df2e56Smrg    swapl(&stuff->drawable);
1466f7df2e56Smrg    swaps(&stuff->width);
1467f7df2e56Smrg    swaps(&stuff->height);
1468f7df2e56Smrg    swapl(&stuff->shmseg);
1469f7df2e56Smrg    swapl(&stuff->offset);
147005b261ecSmrg    return ProcShmCreatePixmap(client);
147105b261ecSmrg}
147205b261ecSmrg
1473f7df2e56Smrg#ifdef SHM_FD_PASSING
14747e31ba66Smrgstatic int _X_COLD
1475f7df2e56SmrgSProcShmAttachFd(ClientPtr client)
1476f7df2e56Smrg{
1477f7df2e56Smrg    REQUEST(xShmAttachFdReq);
1478f7df2e56Smrg    SetReqFds(client, 1);
1479f7df2e56Smrg    swaps(&stuff->length);
1480f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmAttachFdReq);
1481f7df2e56Smrg    swapl(&stuff->shmseg);
1482f7df2e56Smrg    return ProcShmAttachFd(client);
1483f7df2e56Smrg}
1484f7df2e56Smrg
14857e31ba66Smrgstatic int _X_COLD
1486f7df2e56SmrgSProcShmCreateSegment(ClientPtr client)
1487f7df2e56Smrg{
1488f7df2e56Smrg    REQUEST(xShmCreateSegmentReq);
1489f7df2e56Smrg    swaps(&stuff->length);
1490f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
1491f7df2e56Smrg    swapl(&stuff->shmseg);
1492f7df2e56Smrg    swapl(&stuff->size);
1493f7df2e56Smrg    return ProcShmCreateSegment(client);
1494f7df2e56Smrg}
1495f7df2e56Smrg#endif  /* SHM_FD_PASSING */
1496f7df2e56Smrg
14977e31ba66Smrgstatic int _X_COLD
1498f7df2e56SmrgSProcShmDispatch(ClientPtr client)
149905b261ecSmrg{
150005b261ecSmrg    REQUEST(xReq);
15017e31ba66Smrg
15027e31ba66Smrg    if (stuff->data == X_ShmQueryVersion)
1503f7df2e56Smrg        return SProcShmQueryVersion(client);
15047e31ba66Smrg
15057e31ba66Smrg    if (!client->local)
15067e31ba66Smrg        return BadRequest;
15077e31ba66Smrg
15087e31ba66Smrg    switch (stuff->data) {
150905b261ecSmrg    case X_ShmAttach:
1510f7df2e56Smrg        return SProcShmAttach(client);
151105b261ecSmrg    case X_ShmDetach:
1512f7df2e56Smrg        return SProcShmDetach(client);
151305b261ecSmrg    case X_ShmPutImage:
1514f7df2e56Smrg        return SProcShmPutImage(client);
151505b261ecSmrg    case X_ShmGetImage:
1516f7df2e56Smrg        return SProcShmGetImage(client);
151705b261ecSmrg    case X_ShmCreatePixmap:
1518f7df2e56Smrg        return SProcShmCreatePixmap(client);
1519f7df2e56Smrg#ifdef SHM_FD_PASSING
1520f7df2e56Smrg    case X_ShmAttachFd:
1521f7df2e56Smrg        return SProcShmAttachFd(client);
1522f7df2e56Smrg    case X_ShmCreateSegment:
1523f7df2e56Smrg        return SProcShmCreateSegment(client);
1524f7df2e56Smrg#endif
152505b261ecSmrg    default:
1526f7df2e56Smrg        return BadRequest;
152705b261ecSmrg    }
152805b261ecSmrg}
152965b04b38Smrg
153065b04b38Smrgvoid
1531f7df2e56SmrgShmExtensionInit(void)
153265b04b38Smrg{
153365b04b38Smrg    ExtensionEntry *extEntry;
153465b04b38Smrg    int i;
153565b04b38Smrg
153665b04b38Smrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL
1537f7df2e56Smrg    if (!CheckForShmSyscall()) {
1538f7df2e56Smrg        ErrorF("MIT-SHM extension disabled due to lack of kernel support\n");
1539f7df2e56Smrg        return;
154065b04b38Smrg    }
154165b04b38Smrg#endif
154265b04b38Smrg
154365b04b38Smrg    if (!ShmRegisterPrivates())
1544f7df2e56Smrg        return;
154565b04b38Smrg
154665b04b38Smrg    sharedPixmaps = xFalse;
154765b04b38Smrg    {
1548f7df2e56Smrg        sharedPixmaps = xTrue;
1549f7df2e56Smrg        for (i = 0; i < screenInfo.numScreens; i++) {
1550f7df2e56Smrg            ShmScrPrivateRec *screen_priv =
1551f7df2e56Smrg                ShmInitScreenPriv(screenInfo.screens[i]);
1552f7df2e56Smrg            if (!screen_priv->shmFuncs)
1553f7df2e56Smrg                screen_priv->shmFuncs = &miFuncs;
1554f7df2e56Smrg            if (!screen_priv->shmFuncs->CreatePixmap)
1555f7df2e56Smrg                sharedPixmaps = xFalse;
1556f7df2e56Smrg        }
1557f7df2e56Smrg        if (sharedPixmaps)
1558f7df2e56Smrg            for (i = 0; i < screenInfo.numScreens; i++) {
1559f7df2e56Smrg                ShmScrPrivateRec *screen_priv =
1560f7df2e56Smrg                    ShmGetScreenPriv(screenInfo.screens[i]);
1561f7df2e56Smrg                screen_priv->destroyPixmap =
1562f7df2e56Smrg                    screenInfo.screens[i]->DestroyPixmap;
1563f7df2e56Smrg                screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap;
1564f7df2e56Smrg            }
156565b04b38Smrg    }
156665b04b38Smrg    ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg");
156765b04b38Smrg    if (ShmSegType &&
1568f7df2e56Smrg        (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors,
1569f7df2e56Smrg                                 ProcShmDispatch, SProcShmDispatch,
1570f7df2e56Smrg                                 ShmResetProc, StandardMinorOpcode))) {
1571f7df2e56Smrg        ShmReqCode = (unsigned char) extEntry->base;
1572f7df2e56Smrg        ShmCompletionCode = extEntry->eventBase;
1573f7df2e56Smrg        BadShmSegCode = extEntry->errorBase;
1574f7df2e56Smrg        SetResourceTypeErrorValue(ShmSegType, BadShmSegCode);
1575f7df2e56Smrg        EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent;
157665b04b38Smrg    }
157765b04b38Smrg}
1578