shm.c revision 7e31ba66
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
15705b261ecSmrgstatic Bool badSysCall = FALSE;
15805b261ecSmrg
15905b261ecSmrgstatic void
1604642e01fSmrgSigSysHandler(int signo)
16105b261ecSmrg{
16205b261ecSmrg    badSysCall = TRUE;
16305b261ecSmrg}
16405b261ecSmrg
165f7df2e56Smrgstatic Bool
166f7df2e56SmrgCheckForShmSyscall(void)
16705b261ecSmrg{
168f7df2e56Smrg    void (*oldHandler) (int);
16905b261ecSmrg    int shmid = -1;
17005b261ecSmrg
17105b261ecSmrg    /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
1727e31ba66Smrg    oldHandler = OsSignal(SIGSYS, SigSysHandler);
17305b261ecSmrg
17405b261ecSmrg    badSysCall = FALSE;
17505b261ecSmrg    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
17605b261ecSmrg
177f7df2e56Smrg    if (shmid != -1) {
17805b261ecSmrg        /* Successful allocation - clean up */
179f7df2e56Smrg        shmctl(shmid, IPC_RMID, NULL);
18005b261ecSmrg    }
181f7df2e56Smrg    else {
18205b261ecSmrg        /* Allocation failed */
18305b261ecSmrg        badSysCall = TRUE;
18405b261ecSmrg    }
1857e31ba66Smrg    OsSignal(SIGSYS, oldHandler);
1864202a189Smrg    return !badSysCall;
18705b261ecSmrg}
18805b261ecSmrg
18905b261ecSmrg#define MUST_CHECK_FOR_SHM_SYSCALL
19005b261ecSmrg
19105b261ecSmrg#endif
19205b261ecSmrg
1934202a189Smrgstatic Bool
194f7df2e56SmrgShmCloseScreen(ScreenPtr pScreen)
1954202a189Smrg{
1964202a189Smrg    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
197f7df2e56Smrg
1984202a189Smrg    pScreen->CloseScreen = screen_priv->CloseScreen;
1994202a189Smrg    dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL);
2004202a189Smrg    free(screen_priv);
201f7df2e56Smrg    return (*pScreen->CloseScreen) (pScreen);
2024202a189Smrg}
2034202a189Smrg
2044202a189Smrgstatic ShmScrPrivateRec *
2054202a189SmrgShmInitScreenPriv(ScreenPtr pScreen)
2064202a189Smrg{
2074202a189Smrg    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
208f7df2e56Smrg
209f7df2e56Smrg    if (!screen_priv) {
210f7df2e56Smrg        screen_priv = calloc(1, sizeof(ShmScrPrivateRec));
211f7df2e56Smrg        screen_priv->CloseScreen = pScreen->CloseScreen;
212f7df2e56Smrg        dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv);
213f7df2e56Smrg        pScreen->CloseScreen = ShmCloseScreen;
2144202a189Smrg    }
2154202a189Smrg    return screen_priv;
2164202a189Smrg}
2174202a189Smrg
2184202a189Smrgstatic Bool
2194202a189SmrgShmRegisterPrivates(void)
2204202a189Smrg{
2214202a189Smrg    if (!dixRegisterPrivateKey(&shmScrPrivateKeyRec, PRIVATE_SCREEN, 0))
222f7df2e56Smrg        return FALSE;
2234202a189Smrg    if (!dixRegisterPrivateKey(&shmPixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
224f7df2e56Smrg        return FALSE;
2254202a189Smrg    return TRUE;
2264202a189Smrg}
2274202a189Smrg
228f7df2e56Smrg /*ARGSUSED*/ static void
229f7df2e56SmrgShmResetProc(ExtensionEntry * extEntry)
23005b261ecSmrg{
23105b261ecSmrg    int i;
232f7df2e56Smrg
2334202a189Smrg    for (i = 0; i < screenInfo.numScreens; i++)
234f7df2e56Smrg        ShmRegisterFuncs(screenInfo.screens[i], NULL);
23505b261ecSmrg}
23605b261ecSmrg
2374202a189Smrgvoid
2384642e01fSmrgShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs)
23905b261ecSmrg{
2404202a189Smrg    if (!ShmRegisterPrivates())
241f7df2e56Smrg        return;
2424202a189Smrg    ShmInitScreenPriv(pScreen)->shmFuncs = funcs;
24305b261ecSmrg}
24405b261ecSmrg
24505b261ecSmrgstatic Bool
246f7df2e56SmrgShmDestroyPixmap(PixmapPtr pPixmap)
24705b261ecSmrg{
248f7df2e56Smrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
2494202a189Smrg    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
250f7df2e56Smrg    void *shmdesc = NULL;
251f7df2e56Smrg    Bool ret;
252f7df2e56Smrg
25305b261ecSmrg    if (pPixmap->refcnt == 1)
254f7df2e56Smrg        shmdesc = dixLookupPrivate(&pPixmap->devPrivates, shmPixmapPrivateKey);
255f7df2e56Smrg
2564202a189Smrg    pScreen->DestroyPixmap = screen_priv->destroyPixmap;
25705b261ecSmrg    ret = (*pScreen->DestroyPixmap) (pPixmap);
2584202a189Smrg    screen_priv->destroyPixmap = pScreen->DestroyPixmap;
25905b261ecSmrg    pScreen->DestroyPixmap = ShmDestroyPixmap;
260f7df2e56Smrg
261f7df2e56Smrg    if (shmdesc)
262f7df2e56Smrg	ShmDetachSegment(shmdesc, 0);
263f7df2e56Smrg
26405b261ecSmrg    return ret;
26505b261ecSmrg}
26605b261ecSmrg
2674202a189Smrgvoid
2684642e01fSmrgShmRegisterFbFuncs(ScreenPtr pScreen)
26905b261ecSmrg{
2704202a189Smrg    ShmRegisterFuncs(pScreen, &fbFuncs);
27105b261ecSmrg}
27205b261ecSmrg
27305b261ecSmrgstatic int
2744642e01fSmrgProcShmQueryVersion(ClientPtr client)
27505b261ecSmrg{
276f7df2e56Smrg    xShmQueryVersionReply rep = {
277f7df2e56Smrg        .type = X_Reply,
278f7df2e56Smrg        .sharedPixmaps = sharedPixmaps,
279f7df2e56Smrg        .sequenceNumber = client->sequence,
280f7df2e56Smrg        .length = 0,
281f7df2e56Smrg        .majorVersion = SERVER_SHM_MAJOR_VERSION,
282f7df2e56Smrg        .minorVersion = SERVER_SHM_MINOR_VERSION,
283f7df2e56Smrg        .uid = geteuid(),
284f7df2e56Smrg        .gid = getegid(),
285f7df2e56Smrg        .pixmapFormat = sharedPixmaps ? ZPixmap : 0
286f7df2e56Smrg    };
28705b261ecSmrg
28805b261ecSmrg    REQUEST_SIZE_MATCH(xShmQueryVersionReq);
289f7df2e56Smrg
29005b261ecSmrg    if (client->swapped) {
291f7df2e56Smrg        swaps(&rep.sequenceNumber);
292f7df2e56Smrg        swapl(&rep.length);
293f7df2e56Smrg        swaps(&rep.majorVersion);
294f7df2e56Smrg        swaps(&rep.minorVersion);
295f7df2e56Smrg        swaps(&rep.uid);
296f7df2e56Smrg        swaps(&rep.gid);
297f7df2e56Smrg    }
298f7df2e56Smrg    WriteToClient(client, sizeof(xShmQueryVersionReply), &rep);
2994202a189Smrg    return Success;
30005b261ecSmrg}
30105b261ecSmrg
30205b261ecSmrg/*
30305b261ecSmrg * Simulate the access() system call for a shared memory segement,
30405b261ecSmrg * using the credentials from the client if available
30505b261ecSmrg */
30605b261ecSmrgstatic int
307f7df2e56Smrgshm_access(ClientPtr client, SHMPERM_TYPE * perm, int readonly)
30805b261ecSmrg{
30905b261ecSmrg    int uid, gid;
31005b261ecSmrg    mode_t mask;
3114642e01fSmrg    int uidset = 0, gidset = 0;
3124642e01fSmrg    LocalClientCredRec *lcc;
313f7df2e56Smrg
3144642e01fSmrg    if (GetLocalClientCreds(client, &lcc) != -1) {
31505b261ecSmrg
316f7df2e56Smrg        if (lcc->fieldsSet & LCC_UID_SET) {
317f7df2e56Smrg            uid = lcc->euid;
318f7df2e56Smrg            uidset = 1;
319f7df2e56Smrg        }
320f7df2e56Smrg        if (lcc->fieldsSet & LCC_GID_SET) {
321f7df2e56Smrg            gid = lcc->egid;
322f7df2e56Smrg            gidset = 1;
323f7df2e56Smrg        }
3244642e01fSmrg
3254642e01fSmrg#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID)
326f7df2e56Smrg        if (((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1)
327f7df2e56Smrg            || (lcc->zoneid != SHMPERM_ZONEID(perm))) {
328f7df2e56Smrg            uidset = 0;
329f7df2e56Smrg            gidset = 0;
330f7df2e56Smrg        }
3314642e01fSmrg#endif
332f7df2e56Smrg        FreeLocalClientCreds(lcc);
333f7df2e56Smrg
334f7df2e56Smrg        if (uidset) {
335f7df2e56Smrg            /* User id 0 always gets access */
336f7df2e56Smrg            if (uid == 0) {
337f7df2e56Smrg                return 0;
338f7df2e56Smrg            }
339f7df2e56Smrg            /* Check the owner */
340f7df2e56Smrg            if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) {
341f7df2e56Smrg                mask = S_IRUSR;
342f7df2e56Smrg                if (!readonly) {
343f7df2e56Smrg                    mask |= S_IWUSR;
344f7df2e56Smrg                }
345f7df2e56Smrg                return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
346f7df2e56Smrg            }
347f7df2e56Smrg        }
348f7df2e56Smrg
349f7df2e56Smrg        if (gidset) {
350f7df2e56Smrg            /* Check the group */
351f7df2e56Smrg            if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) {
352f7df2e56Smrg                mask = S_IRGRP;
353f7df2e56Smrg                if (!readonly) {
354f7df2e56Smrg                    mask |= S_IWGRP;
355f7df2e56Smrg                }
356f7df2e56Smrg                return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
357f7df2e56Smrg            }
358f7df2e56Smrg        }
35905b261ecSmrg    }
36005b261ecSmrg    /* Otherwise, check everyone else */
36105b261ecSmrg    mask = S_IROTH;
36205b261ecSmrg    if (!readonly) {
363f7df2e56Smrg        mask |= S_IWOTH;
36405b261ecSmrg    }
3654642e01fSmrg    return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
36605b261ecSmrg}
36705b261ecSmrg
36805b261ecSmrgstatic int
3694642e01fSmrgProcShmAttach(ClientPtr client)
37005b261ecSmrg{
3714642e01fSmrg    SHMSTAT_TYPE buf;
37205b261ecSmrg    ShmDescPtr shmdesc;
373f7df2e56Smrg
37405b261ecSmrg    REQUEST(xShmAttachReq);
37505b261ecSmrg
37605b261ecSmrg    REQUEST_SIZE_MATCH(xShmAttachReq);
37705b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
378f7df2e56Smrg    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
379f7df2e56Smrg        client->errorValue = stuff->readOnly;
3804202a189Smrg        return BadValue;
38105b261ecSmrg    }
382f7df2e56Smrg    for (shmdesc = Shmsegs; shmdesc; shmdesc = shmdesc->next) {
383f7df2e56Smrg        if (!SHMDESC_IS_FD(shmdesc) && shmdesc->shmid == stuff->shmid)
384f7df2e56Smrg            break;
38505b261ecSmrg    }
386f7df2e56Smrg    if (shmdesc) {
387f7df2e56Smrg        if (!stuff->readOnly && !shmdesc->writable)
388f7df2e56Smrg            return BadAccess;
389f7df2e56Smrg        shmdesc->refcnt++;
390f7df2e56Smrg    }
391f7df2e56Smrg    else {
392f7df2e56Smrg        shmdesc = malloc(sizeof(ShmDescRec));
393f7df2e56Smrg        if (!shmdesc)
394f7df2e56Smrg            return BadAlloc;
395f7df2e56Smrg#ifdef SHM_FD_PASSING
396f7df2e56Smrg        shmdesc->is_fd = FALSE;
397f7df2e56Smrg#endif
398f7df2e56Smrg        shmdesc->addr = shmat(stuff->shmid, 0,
399f7df2e56Smrg                              stuff->readOnly ? SHM_RDONLY : 0);
400f7df2e56Smrg        if ((shmdesc->addr == ((char *) -1)) || SHMSTAT(stuff->shmid, &buf)) {
401f7df2e56Smrg            free(shmdesc);
402f7df2e56Smrg            return BadAccess;
403f7df2e56Smrg        }
404f7df2e56Smrg
405f7df2e56Smrg        /* The attach was performed with root privs. We must
406f7df2e56Smrg         * do manual checking of access rights for the credentials
407f7df2e56Smrg         * of the client */
408f7df2e56Smrg
409f7df2e56Smrg        if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) {
410f7df2e56Smrg            shmdt(shmdesc->addr);
411f7df2e56Smrg            free(shmdesc);
412f7df2e56Smrg            return BadAccess;
413f7df2e56Smrg        }
414f7df2e56Smrg
415f7df2e56Smrg        shmdesc->shmid = stuff->shmid;
416f7df2e56Smrg        shmdesc->refcnt = 1;
417f7df2e56Smrg        shmdesc->writable = !stuff->readOnly;
418f7df2e56Smrg        shmdesc->size = SHM_SEGSZ(buf);
419f7df2e56Smrg        shmdesc->next = Shmsegs;
420f7df2e56Smrg        Shmsegs = shmdesc;
42105b261ecSmrg    }
422f7df2e56Smrg    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
423f7df2e56Smrg        return BadAlloc;
4244202a189Smrg    return Success;
42505b261ecSmrg}
42605b261ecSmrg
427f7df2e56Smrg /*ARGSUSED*/ static int
428f7df2e56SmrgShmDetachSegment(void *value, /* must conform to DeleteType */
429f7df2e56Smrg                 XID unused)
43005b261ecSmrg{
431f7df2e56Smrg    ShmDescPtr shmdesc = (ShmDescPtr) value;
43205b261ecSmrg    ShmDescPtr *prev;
43305b261ecSmrg
43405b261ecSmrg    if (--shmdesc->refcnt)
435f7df2e56Smrg        return TRUE;
436f7df2e56Smrg#if SHM_FD_PASSING
437f7df2e56Smrg    if (shmdesc->is_fd) {
438f7df2e56Smrg        if (shmdesc->busfault)
439f7df2e56Smrg            busfault_unregister(shmdesc->busfault);
440f7df2e56Smrg        munmap(shmdesc->addr, shmdesc->size);
441f7df2e56Smrg    } else
442f7df2e56Smrg#endif
443f7df2e56Smrg        shmdt(shmdesc->addr);
444f7df2e56Smrg    for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next);
44505b261ecSmrg    *prev = shmdesc->next;
4464202a189Smrg    free(shmdesc);
44705b261ecSmrg    return Success;
44805b261ecSmrg}
44905b261ecSmrg
45005b261ecSmrgstatic int
4514642e01fSmrgProcShmDetach(ClientPtr client)
45205b261ecSmrg{
45305b261ecSmrg    ShmDescPtr shmdesc;
454f7df2e56Smrg
45505b261ecSmrg    REQUEST(xShmDetachReq);
45605b261ecSmrg
45705b261ecSmrg    REQUEST_SIZE_MATCH(xShmDetachReq);
45805b261ecSmrg    VERIFY_SHMSEG(stuff->shmseg, shmdesc, client);
45905b261ecSmrg    FreeResource(stuff->shmseg, RT_NONE);
4604202a189Smrg    return Success;
46105b261ecSmrg}
46205b261ecSmrg
4634642e01fSmrg/*
4644642e01fSmrg * If the given request doesn't exactly match PutImage's constraints,
4654642e01fSmrg * wrap the image in a scratch pixmap header and let CopyArea sort it out.
4664642e01fSmrg */
46705b261ecSmrgstatic void
4684642e01fSmrgdoShmPutImage(DrawablePtr dst, GCPtr pGC,
469f7df2e56Smrg              int depth, unsigned int format,
470f7df2e56Smrg              int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
471f7df2e56Smrg              char *data)
47205b261ecSmrg{
4734642e01fSmrg    PixmapPtr pPixmap;
4744202a189Smrg
47545bb0b75Smrg    if (format == ZPixmap || (format == XYPixmap && depth == 1)) {
476f7df2e56Smrg        pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth,
477f7df2e56Smrg                                         BitsPerPixel(depth),
478f7df2e56Smrg                                         PixmapBytePad(w, depth), data);
479f7df2e56Smrg        if (!pPixmap)
480f7df2e56Smrg            return;
481f7df2e56Smrg        pGC->ops->CopyArea((DrawablePtr) pPixmap, dst, pGC, sx, sy, sw, sh, dx,
482f7df2e56Smrg                           dy);
483f7df2e56Smrg        FreeScratchPixmapHeader(pPixmap);
484f7df2e56Smrg    }
485f7df2e56Smrg    else {
486f7df2e56Smrg        GCPtr putGC = GetScratchGC(depth, dst->pScreen);
487f7df2e56Smrg
488f7df2e56Smrg        if (!putGC)
489f7df2e56Smrg            return;
490f7df2e56Smrg
491f7df2e56Smrg        pPixmap = (*dst->pScreen->CreatePixmap) (dst->pScreen, sw, sh, depth,
492f7df2e56Smrg                                                 CREATE_PIXMAP_USAGE_SCRATCH);
493f7df2e56Smrg        if (!pPixmap) {
494f7df2e56Smrg            FreeScratchGC(putGC);
495f7df2e56Smrg            return;
496f7df2e56Smrg        }
497f7df2e56Smrg        ValidateGC(&pPixmap->drawable, putGC);
498f7df2e56Smrg        (*putGC->ops->PutImage) (&pPixmap->drawable, putGC, depth, -sx, -sy, w,
499f7df2e56Smrg                                 h, 0,
500f7df2e56Smrg                                 (format == XYPixmap) ? XYPixmap : ZPixmap,
501f7df2e56Smrg                                 data);
502f7df2e56Smrg        FreeScratchGC(putGC);
503f7df2e56Smrg        if (format == XYBitmap)
504f7df2e56Smrg            (void) (*pGC->ops->CopyPlane) (&pPixmap->drawable, dst, pGC, 0, 0,
505f7df2e56Smrg                                           sw, sh, dx, dy, 1L);
506f7df2e56Smrg        else
507f7df2e56Smrg            (void) (*pGC->ops->CopyArea) (&pPixmap->drawable, dst, pGC, 0, 0,
508f7df2e56Smrg                                          sw, sh, dx, dy);
509f7df2e56Smrg        (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap);
5104202a189Smrg    }
51105b261ecSmrg}
51205b261ecSmrg
51365b04b38Smrgstatic int
51465b04b38SmrgProcShmPutImage(ClientPtr client)
51505b261ecSmrg{
51665b04b38Smrg    GCPtr pGC;
51765b04b38Smrg    DrawablePtr pDraw;
51865b04b38Smrg    long length;
51965b04b38Smrg    ShmDescPtr shmdesc;
520f7df2e56Smrg
52105b261ecSmrg    REQUEST(xShmPutImageReq);
52265b04b38Smrg
52305b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
52465b04b38Smrg    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
52565b04b38Smrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client);
52665b04b38Smrg    if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse))
527f7df2e56Smrg        return BadValue;
528f7df2e56Smrg    if (stuff->format == XYBitmap) {
52965b04b38Smrg        if (stuff->depth != 1)
53065b04b38Smrg            return BadMatch;
53165b04b38Smrg        length = PixmapBytePad(stuff->totalWidth, 1);
53265b04b38Smrg    }
533f7df2e56Smrg    else if (stuff->format == XYPixmap) {
53465b04b38Smrg        if (pDraw->depth != stuff->depth)
53565b04b38Smrg            return BadMatch;
53665b04b38Smrg        length = PixmapBytePad(stuff->totalWidth, 1);
537f7df2e56Smrg        length *= stuff->depth;
53865b04b38Smrg    }
539f7df2e56Smrg    else if (stuff->format == ZPixmap) {
54065b04b38Smrg        if (pDraw->depth != stuff->depth)
54165b04b38Smrg            return BadMatch;
54265b04b38Smrg        length = PixmapBytePad(stuff->totalWidth, stuff->depth);
54365b04b38Smrg    }
544f7df2e56Smrg    else {
545f7df2e56Smrg        client->errorValue = stuff->format;
54665b04b38Smrg        return BadValue;
54765b04b38Smrg    }
54805b261ecSmrg
54965b04b38Smrg    /*
55065b04b38Smrg     * There's a potential integer overflow in this check:
55165b04b38Smrg     * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight,
55265b04b38Smrg     *                client);
55365b04b38Smrg     * the version below ought to avoid it
55465b04b38Smrg     */
55565b04b38Smrg    if (stuff->totalHeight != 0 &&
556f7df2e56Smrg        length > (shmdesc->size - stuff->offset) / stuff->totalHeight) {
557f7df2e56Smrg        client->errorValue = stuff->totalWidth;
558f7df2e56Smrg        return BadValue;
55965b04b38Smrg    }
560f7df2e56Smrg    if (stuff->srcX > stuff->totalWidth) {
561f7df2e56Smrg        client->errorValue = stuff->srcX;
562f7df2e56Smrg        return BadValue;
56365b04b38Smrg    }
564f7df2e56Smrg    if (stuff->srcY > stuff->totalHeight) {
565f7df2e56Smrg        client->errorValue = stuff->srcY;
566f7df2e56Smrg        return BadValue;
56765b04b38Smrg    }
568f7df2e56Smrg    if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) {
569f7df2e56Smrg        client->errorValue = stuff->srcWidth;
570f7df2e56Smrg        return BadValue;
57165b04b38Smrg    }
572f7df2e56Smrg    if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) {
573f7df2e56Smrg        client->errorValue = stuff->srcHeight;
574f7df2e56Smrg        return BadValue;
57565b04b38Smrg    }
57605b261ecSmrg
57765b04b38Smrg    if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) ||
578f7df2e56Smrg         ((stuff->format != ZPixmap) &&
579f7df2e56Smrg          (stuff->srcX < screenInfo.bitmapScanlinePad) &&
580f7df2e56Smrg          ((stuff->format == XYBitmap) ||
581f7df2e56Smrg           ((stuff->srcY == 0) &&
582f7df2e56Smrg            (stuff->srcHeight == stuff->totalHeight))))) &&
583f7df2e56Smrg        ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth))
584f7df2e56Smrg        (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth,
585f7df2e56Smrg                               stuff->dstX, stuff->dstY,
586f7df2e56Smrg                               stuff->totalWidth, stuff->srcHeight,
587f7df2e56Smrg                               stuff->srcX, stuff->format,
588f7df2e56Smrg                               shmdesc->addr + stuff->offset +
589f7df2e56Smrg                               (stuff->srcY * length));
59065b04b38Smrg    else
591f7df2e56Smrg        doShmPutImage(pDraw, pGC, stuff->depth, stuff->format,
592f7df2e56Smrg                      stuff->totalWidth, stuff->totalHeight,
593f7df2e56Smrg                      stuff->srcX, stuff->srcY,
594f7df2e56Smrg                      stuff->srcWidth, stuff->srcHeight,
595f7df2e56Smrg                      stuff->dstX, stuff->dstY, shmdesc->addr + stuff->offset);
596f7df2e56Smrg
597f7df2e56Smrg    if (stuff->sendEvent) {
598f7df2e56Smrg        xShmCompletionEvent ev = {
599f7df2e56Smrg            .type = ShmCompletionCode,
600f7df2e56Smrg            .drawable = stuff->drawable,
601f7df2e56Smrg            .minorEvent = X_ShmPutImage,
602f7df2e56Smrg            .majorEvent = ShmReqCode,
603f7df2e56Smrg            .shmseg = stuff->shmseg,
604f7df2e56Smrg            .offset = stuff->offset
605f7df2e56Smrg        };
606f7df2e56Smrg        WriteEventsToClient(client, 1, (xEvent *) &ev);
60705b261ecSmrg    }
60865b04b38Smrg
60965b04b38Smrg    return Success;
61005b261ecSmrg}
61105b261ecSmrg
61265b04b38Smrgstatic int
61365b04b38SmrgProcShmGetImage(ClientPtr client)
61405b261ecSmrg{
615f7df2e56Smrg    DrawablePtr pDraw;
616f7df2e56Smrg    long lenPer = 0, length;
617f7df2e56Smrg    Mask plane = 0;
618f7df2e56Smrg    xShmGetImageReply xgi;
619f7df2e56Smrg    ShmDescPtr shmdesc;
620f7df2e56Smrg    VisualID visual = None;
621f7df2e56Smrg    RegionPtr pVisibleRegion = NULL;
622f7df2e56Smrg    int rc;
62305b261ecSmrg
62405b261ecSmrg    REQUEST(xShmGetImageReq);
62505b261ecSmrg
62605b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
627f7df2e56Smrg    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
628f7df2e56Smrg        client->errorValue = stuff->format;
6294202a189Smrg        return BadValue;
63005b261ecSmrg    }
631f7df2e56Smrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
63205b261ecSmrg    if (rc != Success)
633f7df2e56Smrg        return rc;
63405b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
635f7df2e56Smrg    if (pDraw->type == DRAWABLE_WINDOW) {
636f7df2e56Smrg        if (   /* check for being viewable */
637f7df2e56Smrg               !((WindowPtr) pDraw)->realized ||
638f7df2e56Smrg               /* check for being on screen */
639f7df2e56Smrg               pDraw->x + stuff->x < 0 ||
640f7df2e56Smrg               pDraw->x + stuff->x + (int) stuff->width > pDraw->pScreen->width
641f7df2e56Smrg               || pDraw->y + stuff->y < 0 ||
642f7df2e56Smrg               pDraw->y + stuff->y + (int) stuff->height >
643f7df2e56Smrg               pDraw->pScreen->height ||
644f7df2e56Smrg               /* check for being inside of border */
645f7df2e56Smrg               stuff->x < -wBorderWidth((WindowPtr) pDraw) ||
646f7df2e56Smrg               stuff->x + (int) stuff->width >
647f7df2e56Smrg               wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
648f7df2e56Smrg               stuff->y < -wBorderWidth((WindowPtr) pDraw) ||
649f7df2e56Smrg               stuff->y + (int) stuff->height >
650f7df2e56Smrg               wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
651f7df2e56Smrg            return BadMatch;
652f7df2e56Smrg        visual = wVisual(((WindowPtr) pDraw));
6537e31ba66Smrg        if (pDraw->type == DRAWABLE_WINDOW)
6547e31ba66Smrg            pVisibleRegion = &((WindowPtr) pDraw)->borderClip;
65565b04b38Smrg    }
656f7df2e56Smrg    else {
657f7df2e56Smrg        if (stuff->x < 0 ||
658f7df2e56Smrg            stuff->x + (int) stuff->width > pDraw->width ||
659f7df2e56Smrg            stuff->y < 0 || stuff->y + (int) stuff->height > pDraw->height)
660f7df2e56Smrg            return BadMatch;
661f7df2e56Smrg        visual = None;
66265b04b38Smrg    }
663f7df2e56Smrg    xgi = (xShmGetImageReply) {
664f7df2e56Smrg        .type = X_Reply,
665f7df2e56Smrg        .sequenceNumber = client->sequence,
666f7df2e56Smrg        .length = 0,
667f7df2e56Smrg        .visual = visual,
668f7df2e56Smrg        .depth = pDraw->depth
669f7df2e56Smrg    };
670f7df2e56Smrg    if (stuff->format == ZPixmap) {
671f7df2e56Smrg        length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height;
672f7df2e56Smrg    }
673f7df2e56Smrg    else {
674f7df2e56Smrg        lenPer = PixmapBytePad(stuff->width, 1) * stuff->height;
675f7df2e56Smrg        plane = ((Mask) 1) << (pDraw->depth - 1);
676f7df2e56Smrg        /* only planes asked for */
677f7df2e56Smrg        length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
67865b04b38Smrg    }
67965b04b38Smrg
68065b04b38Smrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
68165b04b38Smrg    xgi.size = length;
68265b04b38Smrg
683f7df2e56Smrg    if (length == 0) {
684f7df2e56Smrg        /* nothing to do */
68565b04b38Smrg    }
686f7df2e56Smrg    else if (stuff->format == ZPixmap) {
687f7df2e56Smrg        (*pDraw->pScreen->GetImage) (pDraw, stuff->x, stuff->y,
688f7df2e56Smrg                                     stuff->width, stuff->height,
689f7df2e56Smrg                                     stuff->format, stuff->planeMask,
690f7df2e56Smrg                                     shmdesc->addr + stuff->offset);
691f7df2e56Smrg        if (pVisibleRegion)
692f7df2e56Smrg            XaceCensorImage(client, pVisibleRegion,
693f7df2e56Smrg                    PixmapBytePad(stuff->width, pDraw->depth), pDraw,
694f7df2e56Smrg                    stuff->x, stuff->y, stuff->width, stuff->height,
695f7df2e56Smrg                    stuff->format, shmdesc->addr + stuff->offset);
69665b04b38Smrg    }
697f7df2e56Smrg    else {
69865b04b38Smrg
699f7df2e56Smrg        length = stuff->offset;
700f7df2e56Smrg        for (; plane; plane >>= 1) {
701f7df2e56Smrg            if (stuff->planeMask & plane) {
702f7df2e56Smrg                (*pDraw->pScreen->GetImage) (pDraw,
703f7df2e56Smrg                                             stuff->x, stuff->y,
704f7df2e56Smrg                                             stuff->width, stuff->height,
705f7df2e56Smrg                                             stuff->format, plane,
706f7df2e56Smrg                                             shmdesc->addr + length);
707f7df2e56Smrg                if (pVisibleRegion)
708f7df2e56Smrg                    XaceCensorImage(client, pVisibleRegion,
709f7df2e56Smrg                            BitmapBytePad(stuff->width), pDraw,
710f7df2e56Smrg                            stuff->x, stuff->y, stuff->width, stuff->height,
711f7df2e56Smrg                            stuff->format, shmdesc->addr + length);
712f7df2e56Smrg                length += lenPer;
713f7df2e56Smrg            }
714f7df2e56Smrg        }
71565b04b38Smrg    }
71665b04b38Smrg
71765b04b38Smrg    if (client->swapped) {
718f7df2e56Smrg        swaps(&xgi.sequenceNumber);
719f7df2e56Smrg        swapl(&xgi.length);
720f7df2e56Smrg        swapl(&xgi.visual);
721f7df2e56Smrg        swapl(&xgi.size);
72265b04b38Smrg    }
723f7df2e56Smrg    WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
72465b04b38Smrg
72565b04b38Smrg    return Success;
72665b04b38Smrg}
72765b04b38Smrg
72865b04b38Smrg#ifdef PANORAMIX
729f7df2e56Smrgstatic int
73065b04b38SmrgProcPanoramiXShmPutImage(ClientPtr client)
73165b04b38Smrg{
732f7df2e56Smrg    int j, result, orig_x, orig_y;
733f7df2e56Smrg    PanoramiXRes *draw, *gc;
734f7df2e56Smrg    Bool sendEvent, isRoot;
73565b04b38Smrg
73665b04b38Smrg    REQUEST(xShmPutImageReq);
73765b04b38Smrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
73865b04b38Smrg
739f7df2e56Smrg    result = dixLookupResourceByClass((void **) &draw, stuff->drawable,
740f7df2e56Smrg                                      XRC_DRAWABLE, client, DixWriteAccess);
74165b04b38Smrg    if (result != Success)
74265b04b38Smrg        return (result == BadValue) ? BadDrawable : result;
74365b04b38Smrg
744f7df2e56Smrg    result = dixLookupResourceByType((void **) &gc, stuff->gc,
745f7df2e56Smrg                                     XRT_GC, client, DixReadAccess);
74665b04b38Smrg    if (result != Success)
74765b04b38Smrg        return result;
74865b04b38Smrg
74965b04b38Smrg    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
75065b04b38Smrg
75165b04b38Smrg    orig_x = stuff->dstX;
75265b04b38Smrg    orig_y = stuff->dstY;
75365b04b38Smrg    sendEvent = stuff->sendEvent;
75465b04b38Smrg    stuff->sendEvent = 0;
75565b04b38Smrg    FOR_NSCREENS(j) {
756f7df2e56Smrg        if (!j)
757f7df2e56Smrg            stuff->sendEvent = sendEvent;
758f7df2e56Smrg        stuff->drawable = draw->info[j].id;
759f7df2e56Smrg        stuff->gc = gc->info[j].id;
760f7df2e56Smrg        if (isRoot) {
761f7df2e56Smrg            stuff->dstX = orig_x - screenInfo.screens[j]->x;
762f7df2e56Smrg            stuff->dstY = orig_y - screenInfo.screens[j]->y;
763f7df2e56Smrg        }
764f7df2e56Smrg        result = ProcShmPutImage(client);
765f7df2e56Smrg        if (result != Success)
766f7df2e56Smrg            break;
76765b04b38Smrg    }
76865b04b38Smrg    return result;
76965b04b38Smrg}
77065b04b38Smrg
771f7df2e56Smrgstatic int
77265b04b38SmrgProcPanoramiXShmGetImage(ClientPtr client)
77365b04b38Smrg{
774f7df2e56Smrg    PanoramiXRes *draw;
775f7df2e56Smrg    DrawablePtr *drawables;
776f7df2e56Smrg    DrawablePtr pDraw;
777f7df2e56Smrg    xShmGetImageReply xgi;
778f7df2e56Smrg    ShmDescPtr shmdesc;
779f7df2e56Smrg    int i, x, y, w, h, format, rc;
780f7df2e56Smrg    Mask plane = 0, planemask;
781f7df2e56Smrg    long lenPer = 0, length, widthBytesLine;
782f7df2e56Smrg    Bool isRoot;
78365b04b38Smrg
78465b04b38Smrg    REQUEST(xShmGetImageReq);
78565b04b38Smrg
78665b04b38Smrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
78765b04b38Smrg
78865b04b38Smrg    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
789f7df2e56Smrg        client->errorValue = stuff->format;
79065b04b38Smrg        return BadValue;
79165b04b38Smrg    }
79265b04b38Smrg
793f7df2e56Smrg    rc = dixLookupResourceByClass((void **) &draw, stuff->drawable,
794f7df2e56Smrg                                  XRC_DRAWABLE, client, DixWriteAccess);
79565b04b38Smrg    if (rc != Success)
796f7df2e56Smrg        return (rc == BadValue) ? BadDrawable : rc;
79765b04b38Smrg
79865b04b38Smrg    if (draw->type == XRT_PIXMAP)
799f7df2e56Smrg        return ProcShmGetImage(client);
80065b04b38Smrg
801f7df2e56Smrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
80265b04b38Smrg    if (rc != Success)
803f7df2e56Smrg        return rc;
80465b04b38Smrg
80565b04b38Smrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
80665b04b38Smrg
80765b04b38Smrg    x = stuff->x;
80865b04b38Smrg    y = stuff->y;
80965b04b38Smrg    w = stuff->width;
81065b04b38Smrg    h = stuff->height;
81165b04b38Smrg    format = stuff->format;
81265b04b38Smrg    planemask = stuff->planeMask;
81365b04b38Smrg
81465b04b38Smrg    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
81565b04b38Smrg
816f7df2e56Smrg    if (isRoot) {
817f7df2e56Smrg        if (                    /* check for being onscreen */
818f7df2e56Smrg               x < 0 || x + w > PanoramiXPixWidth ||
819f7df2e56Smrg               y < 0 || y + h > PanoramiXPixHeight)
820f7df2e56Smrg            return BadMatch;
821f7df2e56Smrg    }
822f7df2e56Smrg    else {
823f7df2e56Smrg        if (                    /* check for being onscreen */
824f7df2e56Smrg               screenInfo.screens[0]->x + pDraw->x + x < 0 ||
825f7df2e56Smrg               screenInfo.screens[0]->x + pDraw->x + x + w > PanoramiXPixWidth
826f7df2e56Smrg               || screenInfo.screens[0]->y + pDraw->y + y < 0 ||
827f7df2e56Smrg               screenInfo.screens[0]->y + pDraw->y + y + h > PanoramiXPixHeight
828f7df2e56Smrg               ||
829f7df2e56Smrg               /* check for being inside of border */
830f7df2e56Smrg               x < -wBorderWidth((WindowPtr) pDraw) ||
831f7df2e56Smrg               x + w > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
832f7df2e56Smrg               y < -wBorderWidth((WindowPtr) pDraw) ||
833f7df2e56Smrg               y + h > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
834f7df2e56Smrg            return BadMatch;
83565b04b38Smrg    }
83665b04b38Smrg
8377e31ba66Smrg    if (format == ZPixmap) {
8387e31ba66Smrg        widthBytesLine = PixmapBytePad(w, pDraw->depth);
8397e31ba66Smrg        length = widthBytesLine * h;
8407e31ba66Smrg    }
8417e31ba66Smrg    else {
8427e31ba66Smrg        widthBytesLine = PixmapBytePad(w, 1);
8437e31ba66Smrg        lenPer = widthBytesLine * h;
8447e31ba66Smrg        plane = ((Mask) 1) << (pDraw->depth - 1);
8457e31ba66Smrg        length = lenPer * Ones(planemask & (plane | (plane - 1)));
8467e31ba66Smrg    }
8477e31ba66Smrg
8487e31ba66Smrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
8497e31ba66Smrg
8504202a189Smrg    drawables = calloc(PanoramiXNumScreens, sizeof(DrawablePtr));
851f7df2e56Smrg    if (!drawables)
852f7df2e56Smrg        return BadAlloc;
8534202a189Smrg
85405b261ecSmrg    drawables[0] = pDraw;
855f7df2e56Smrg    FOR_NSCREENS_FORWARD_SKIP(i) {
856f7df2e56Smrg        rc = dixLookupDrawable(drawables + i, draw->info[i].id, client, 0,
857f7df2e56Smrg                               DixReadAccess);
858f7df2e56Smrg        if (rc != Success) {
859f7df2e56Smrg            free(drawables);
860f7df2e56Smrg            return rc;
861f7df2e56Smrg        }
86205b261ecSmrg    }
86305b261ecSmrg
864f7df2e56Smrg    xgi = (xShmGetImageReply) {
865f7df2e56Smrg        .type = X_Reply,
866f7df2e56Smrg        .sequenceNumber = client->sequence,
867f7df2e56Smrg        .length = 0,
868f7df2e56Smrg        .visual = wVisual(((WindowPtr) pDraw)),
869f7df2e56Smrg        .depth = pDraw->depth
870f7df2e56Smrg    };
871f7df2e56Smrg
87205b261ecSmrg    xgi.size = length;
87305b261ecSmrg
874f7df2e56Smrg    if (length == 0) {          /* nothing to do */
875f7df2e56Smrg    }
87605b261ecSmrg    else if (format == ZPixmap) {
877f7df2e56Smrg        XineramaGetImageData(drawables, x, y, w, h, format, planemask,
878f7df2e56Smrg                             shmdesc->addr + stuff->offset,
879f7df2e56Smrg                             widthBytesLine, isRoot);
880f7df2e56Smrg    }
881f7df2e56Smrg    else {
88205b261ecSmrg
883f7df2e56Smrg        length = stuff->offset;
88405b261ecSmrg        for (; plane; plane >>= 1) {
885f7df2e56Smrg            if (planemask & plane) {
886f7df2e56Smrg                XineramaGetImageData(drawables, x, y, w, h,
887f7df2e56Smrg                                     format, plane, shmdesc->addr + length,
888f7df2e56Smrg                                     widthBytesLine, isRoot);
889f7df2e56Smrg                length += lenPer;
890f7df2e56Smrg            }
891f7df2e56Smrg        }
89205b261ecSmrg    }
8934202a189Smrg    free(drawables);
894f7df2e56Smrg
89505b261ecSmrg    if (client->swapped) {
896f7df2e56Smrg        swaps(&xgi.sequenceNumber);
897f7df2e56Smrg        swapl(&xgi.length);
898f7df2e56Smrg        swapl(&xgi.visual);
899f7df2e56Smrg        swapl(&xgi.size);
90005b261ecSmrg    }
901f7df2e56Smrg    WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
90205b261ecSmrg
9034202a189Smrg    return Success;
90405b261ecSmrg}
90505b261ecSmrg
90605b261ecSmrgstatic int
9074642e01fSmrgProcPanoramiXShmCreatePixmap(ClientPtr client)
90805b261ecSmrg{
90905b261ecSmrg    ScreenPtr pScreen = NULL;
91005b261ecSmrg    PixmapPtr pMap = NULL;
91105b261ecSmrg    DrawablePtr pDraw;
91205b261ecSmrg    DepthPtr pDepth;
91305b261ecSmrg    int i, j, result, rc;
91405b261ecSmrg    ShmDescPtr shmdesc;
915f7df2e56Smrg
91605b261ecSmrg    REQUEST(xShmCreatePixmapReq);
91705b261ecSmrg    unsigned int width, height, depth;
91805b261ecSmrg    unsigned long size;
91905b261ecSmrg    PanoramiXRes *newPix;
92005b261ecSmrg
92105b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
92205b261ecSmrg    client->errorValue = stuff->pid;
92305b261ecSmrg    if (!sharedPixmaps)
924f7df2e56Smrg        return BadImplementation;
92505b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->pid, client);
92605b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
927f7df2e56Smrg                           DixGetAttrAccess);
92805b261ecSmrg    if (rc != Success)
929f7df2e56Smrg        return rc;
93005b261ecSmrg
93105b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
93205b261ecSmrg
93305b261ecSmrg    width = stuff->width;
93405b261ecSmrg    height = stuff->height;
93505b261ecSmrg    depth = stuff->depth;
936f7df2e56Smrg    if (!width || !height || !depth) {
937f7df2e56Smrg        client->errorValue = 0;
93805b261ecSmrg        return BadValue;
93905b261ecSmrg    }
94005b261ecSmrg    if (width > 32767 || height > 32767)
94105b261ecSmrg        return BadAlloc;
94205b261ecSmrg
943f7df2e56Smrg    if (stuff->depth != 1) {
94405b261ecSmrg        pDepth = pDraw->pScreen->allowedDepths;
945f7df2e56Smrg        for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
946f7df2e56Smrg            if (pDepth->depth == stuff->depth)
947f7df2e56Smrg                goto CreatePmap;
948f7df2e56Smrg        client->errorValue = stuff->depth;
94905b261ecSmrg        return BadValue;
95005b261ecSmrg    }
95105b261ecSmrg
952f7df2e56Smrg CreatePmap:
95305b261ecSmrg    size = PixmapBytePad(width, depth) * height;
95405b261ecSmrg    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
95505b261ecSmrg        if (size < width * height)
95605b261ecSmrg            return BadAlloc;
95705b261ecSmrg    }
95805b261ecSmrg    /* thankfully, offset is unsigned */
95905b261ecSmrg    if (stuff->offset + size < size)
960f7df2e56Smrg        return BadAlloc;
96105b261ecSmrg
96205b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
96305b261ecSmrg
964f7df2e56Smrg    if (!(newPix = malloc(sizeof(PanoramiXRes))))
965f7df2e56Smrg        return BadAlloc;
96605b261ecSmrg
96705b261ecSmrg    newPix->type = XRT_PIXMAP;
96805b261ecSmrg    newPix->u.pix.shared = TRUE;
969f7df2e56Smrg    panoramix_setup_ids(newPix, client, stuff->pid);
97005b261ecSmrg
9714202a189Smrg    result = Success;
97205b261ecSmrg
97305b261ecSmrg    FOR_NSCREENS(j) {
974f7df2e56Smrg        ShmScrPrivateRec *screen_priv;
975f7df2e56Smrg
976f7df2e56Smrg        pScreen = screenInfo.screens[j];
977f7df2e56Smrg
978f7df2e56Smrg        screen_priv = ShmGetScreenPriv(pScreen);
979f7df2e56Smrg        pMap = (*screen_priv->shmFuncs->CreatePixmap) (pScreen,
980f7df2e56Smrg                                                       stuff->width,
981f7df2e56Smrg                                                       stuff->height,
982f7df2e56Smrg                                                       stuff->depth,
983f7df2e56Smrg                                                       shmdesc->addr +
984f7df2e56Smrg                                                       stuff->offset);
985f7df2e56Smrg
986f7df2e56Smrg        if (pMap) {
987f7df2e56Smrg            result = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid,
988f7df2e56Smrg                              RT_PIXMAP, pMap, RT_NONE, NULL, DixCreateAccess);
989f7df2e56Smrg            if (result != Success) {
990f7df2e56Smrg                pDraw->pScreen->DestroyPixmap(pMap);
9917e31ba66Smrg                break;
992f7df2e56Smrg            }
993f7df2e56Smrg            dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
99405b261ecSmrg            shmdesc->refcnt++;
995f7df2e56Smrg            pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
996f7df2e56Smrg            pMap->drawable.id = newPix->info[j].id;
997f7df2e56Smrg            if (!AddResource(newPix->info[j].id, RT_PIXMAP, (void *) pMap)) {
998f7df2e56Smrg                result = BadAlloc;
999f7df2e56Smrg                break;
1000f7df2e56Smrg            }
1001f7df2e56Smrg        }
1002f7df2e56Smrg        else {
1003f7df2e56Smrg            result = BadAlloc;
1004f7df2e56Smrg            break;
1005f7df2e56Smrg        }
100605b261ecSmrg    }
100705b261ecSmrg
10087e31ba66Smrg    if (result != Success) {
1009f7df2e56Smrg        while (j--)
1010f7df2e56Smrg            FreeResource(newPix->info[j].id, RT_NONE);
1011f7df2e56Smrg        free(newPix);
1012f7df2e56Smrg    }
1013f7df2e56Smrg    else
1014f7df2e56Smrg        AddResource(stuff->pid, XRT_PIXMAP, newPix);
101505b261ecSmrg
101605b261ecSmrg    return result;
101705b261ecSmrg}
101805b261ecSmrg#endif
101905b261ecSmrg
102005b261ecSmrgstatic PixmapPtr
1021f7df2e56SmrgfbShmCreatePixmap(ScreenPtr pScreen,
1022f7df2e56Smrg                  int width, int height, int depth, char *addr)
102305b261ecSmrg{
10244642e01fSmrg    PixmapPtr pPixmap;
102505b261ecSmrg
1026f7df2e56Smrg    pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0);
102705b261ecSmrg    if (!pPixmap)
1028f7df2e56Smrg        return NullPixmap;
1029f7df2e56Smrg
1030f7df2e56Smrg    if (!(*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth,
1031f7df2e56Smrg                                         BitsPerPixel(depth),
1032f7df2e56Smrg                                         PixmapBytePad(width, depth),
1033f7df2e56Smrg                                         (void *) addr)) {
1034f7df2e56Smrg        (*pScreen->DestroyPixmap) (pPixmap);
1035f7df2e56Smrg        return NullPixmap;
103605b261ecSmrg    }
103705b261ecSmrg    return pPixmap;
103805b261ecSmrg}
103905b261ecSmrg
104005b261ecSmrgstatic int
10414642e01fSmrgProcShmCreatePixmap(ClientPtr client)
104205b261ecSmrg{
104305b261ecSmrg    PixmapPtr pMap;
104405b261ecSmrg    DrawablePtr pDraw;
104505b261ecSmrg    DepthPtr pDepth;
10464642e01fSmrg    int i, rc;
104705b261ecSmrg    ShmDescPtr shmdesc;
10484202a189Smrg    ShmScrPrivateRec *screen_priv;
1049f7df2e56Smrg
105005b261ecSmrg    REQUEST(xShmCreatePixmapReq);
105105b261ecSmrg    unsigned int width, height, depth;
105205b261ecSmrg    unsigned long size;
105305b261ecSmrg
105405b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
105505b261ecSmrg    client->errorValue = stuff->pid;
105605b261ecSmrg    if (!sharedPixmaps)
1057f7df2e56Smrg        return BadImplementation;
105805b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->pid, client);
105905b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
1060f7df2e56Smrg                           DixGetAttrAccess);
106105b261ecSmrg    if (rc != Success)
1062f7df2e56Smrg        return rc;
106305b261ecSmrg
106405b261ecSmrg    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
1065f7df2e56Smrg
106605b261ecSmrg    width = stuff->width;
106705b261ecSmrg    height = stuff->height;
106805b261ecSmrg    depth = stuff->depth;
1069f7df2e56Smrg    if (!width || !height || !depth) {
1070f7df2e56Smrg        client->errorValue = 0;
107105b261ecSmrg        return BadValue;
107205b261ecSmrg    }
107305b261ecSmrg    if (width > 32767 || height > 32767)
1074f7df2e56Smrg        return BadAlloc;
107505b261ecSmrg
1076f7df2e56Smrg    if (stuff->depth != 1) {
107705b261ecSmrg        pDepth = pDraw->pScreen->allowedDepths;
1078f7df2e56Smrg        for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
1079f7df2e56Smrg            if (pDepth->depth == stuff->depth)
1080f7df2e56Smrg                goto CreatePmap;
1081f7df2e56Smrg        client->errorValue = stuff->depth;
108205b261ecSmrg        return BadValue;
108305b261ecSmrg    }
108405b261ecSmrg
1085f7df2e56Smrg CreatePmap:
108605b261ecSmrg    size = PixmapBytePad(width, depth) * height;
108705b261ecSmrg    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
1088f7df2e56Smrg        if (size < width * height)
1089f7df2e56Smrg            return BadAlloc;
109005b261ecSmrg    }
109105b261ecSmrg    /* thankfully, offset is unsigned */
109205b261ecSmrg    if (stuff->offset + size < size)
1093f7df2e56Smrg        return BadAlloc;
109405b261ecSmrg
109505b261ecSmrg    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
10964202a189Smrg    screen_priv = ShmGetScreenPriv(pDraw->pScreen);
1097f7df2e56Smrg    pMap = (*screen_priv->shmFuncs->CreatePixmap) (pDraw->pScreen, stuff->width,
1098f7df2e56Smrg                                                   stuff->height, stuff->depth,
1099f7df2e56Smrg                                                   shmdesc->addr +
1100f7df2e56Smrg                                                   stuff->offset);
1101f7df2e56Smrg    if (pMap) {
1102f7df2e56Smrg        rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP,
1103f7df2e56Smrg                      pMap, RT_NONE, NULL, DixCreateAccess);
1104f7df2e56Smrg        if (rc != Success) {
1105f7df2e56Smrg            pDraw->pScreen->DestroyPixmap(pMap);
1106f7df2e56Smrg            return rc;
1107f7df2e56Smrg        }
1108f7df2e56Smrg        dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
1109f7df2e56Smrg        shmdesc->refcnt++;
1110f7df2e56Smrg        pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1111f7df2e56Smrg        pMap->drawable.id = stuff->pid;
1112f7df2e56Smrg        if (AddResource(stuff->pid, RT_PIXMAP, (void *) pMap)) {
1113f7df2e56Smrg            return Success;
1114f7df2e56Smrg        }
1115f7df2e56Smrg    }
1116f7df2e56Smrg    return BadAlloc;
1117f7df2e56Smrg}
1118f7df2e56Smrg
1119f7df2e56Smrg#ifdef SHM_FD_PASSING
1120f7df2e56Smrg
1121f7df2e56Smrgstatic void
1122f7df2e56SmrgShmBusfaultNotify(void *context)
1123f7df2e56Smrg{
1124f7df2e56Smrg    ShmDescPtr shmdesc = context;
1125f7df2e56Smrg
1126f7df2e56Smrg    ErrorF("shared memory 0x%x truncated by client\n",
1127f7df2e56Smrg           (unsigned int) shmdesc->resource);
1128f7df2e56Smrg    busfault_unregister(shmdesc->busfault);
1129f7df2e56Smrg    shmdesc->busfault = NULL;
1130f7df2e56Smrg    FreeResource (shmdesc->resource, RT_NONE);
1131f7df2e56Smrg}
1132f7df2e56Smrg
1133f7df2e56Smrgstatic int
1134f7df2e56SmrgProcShmAttachFd(ClientPtr client)
1135f7df2e56Smrg{
1136f7df2e56Smrg    int fd;
1137f7df2e56Smrg    ShmDescPtr shmdesc;
1138f7df2e56Smrg    REQUEST(xShmAttachFdReq);
1139f7df2e56Smrg    struct stat statb;
1140f7df2e56Smrg
1141f7df2e56Smrg    SetReqFds(client, 1);
1142f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmAttachFdReq);
1143f7df2e56Smrg    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
1144f7df2e56Smrg    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1145f7df2e56Smrg        client->errorValue = stuff->readOnly;
1146f7df2e56Smrg        return BadValue;
1147f7df2e56Smrg    }
1148f7df2e56Smrg    fd = ReadFdFromClient(client);
1149f7df2e56Smrg    if (fd < 0)
1150f7df2e56Smrg        return BadMatch;
1151f7df2e56Smrg
1152f7df2e56Smrg    if (fstat(fd, &statb) < 0 || statb.st_size == 0) {
1153f7df2e56Smrg        close(fd);
1154f7df2e56Smrg        return BadMatch;
1155f7df2e56Smrg    }
1156f7df2e56Smrg
1157f7df2e56Smrg    shmdesc = malloc(sizeof(ShmDescRec));
1158f7df2e56Smrg    if (!shmdesc) {
1159f7df2e56Smrg        close(fd);
1160f7df2e56Smrg        return BadAlloc;
1161f7df2e56Smrg    }
1162f7df2e56Smrg    shmdesc->is_fd = TRUE;
1163f7df2e56Smrg    shmdesc->addr = mmap(NULL, statb.st_size,
1164f7df2e56Smrg                         stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1165f7df2e56Smrg                         MAP_SHARED,
1166f7df2e56Smrg                         fd, 0);
1167f7df2e56Smrg
1168f7df2e56Smrg    close(fd);
1169f7df2e56Smrg    if (shmdesc->addr == ((char *) -1)) {
1170f7df2e56Smrg        free(shmdesc);
1171f7df2e56Smrg        return BadAccess;
1172f7df2e56Smrg    }
1173f7df2e56Smrg
1174f7df2e56Smrg    shmdesc->refcnt = 1;
1175f7df2e56Smrg    shmdesc->writable = !stuff->readOnly;
1176f7df2e56Smrg    shmdesc->size = statb.st_size;
1177f7df2e56Smrg    shmdesc->resource = stuff->shmseg;
1178f7df2e56Smrg
1179f7df2e56Smrg    shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1180f7df2e56Smrg    if (!shmdesc->busfault) {
1181f7df2e56Smrg        munmap(shmdesc->addr, shmdesc->size);
1182f7df2e56Smrg        free(shmdesc);
1183f7df2e56Smrg        return BadAlloc;
1184f7df2e56Smrg    }
1185f7df2e56Smrg
1186f7df2e56Smrg    shmdesc->next = Shmsegs;
1187f7df2e56Smrg    Shmsegs = shmdesc;
1188f7df2e56Smrg
1189f7df2e56Smrg    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
1190f7df2e56Smrg        return BadAlloc;
1191f7df2e56Smrg    return Success;
1192f7df2e56Smrg}
1193f7df2e56Smrg
1194f7df2e56Smrgstatic int
1195f7df2e56Smrgshm_tmpfile(void)
1196f7df2e56Smrg{
1197f7df2e56Smrg#ifdef SHMDIR
1198f7df2e56Smrg	int	fd;
1199f7df2e56Smrg	char	template[] = SHMDIR "/shmfd-XXXXXX";
1200f7df2e56Smrg#ifdef O_TMPFILE
1201f7df2e56Smrg	fd = open(SHMDIR, O_TMPFILE|O_RDWR|O_CLOEXEC|O_EXCL, 0666);
1202f7df2e56Smrg	if (fd >= 0) {
12037e31ba66Smrg		DebugF ("Using O_TMPFILE\n");
1204f7df2e56Smrg		return fd;
12054642e01fSmrg	}
1206f7df2e56Smrg	ErrorF ("Not using O_TMPFILE\n");
1207f7df2e56Smrg#endif
12087e31ba66Smrg#ifdef HAVE_MKOSTEMP
12097e31ba66Smrg	fd = mkostemp(template, O_CLOEXEC);
12107e31ba66Smrg#else
1211f7df2e56Smrg	fd = mkstemp(template);
12127e31ba66Smrg#endif
1213f7df2e56Smrg	if (fd < 0)
1214f7df2e56Smrg		return -1;
1215f7df2e56Smrg	unlink(template);
12167e31ba66Smrg#ifndef HAVE_MKOSTEMP
12177e31ba66Smrg	int flags = fcntl(fd, F_GETFD);
12187e31ba66Smrg	if (flags != -1) {
1219f7df2e56Smrg		flags |= FD_CLOEXEC;
1220f7df2e56Smrg		(void) fcntl(fd, F_SETFD, &flags);
122105b261ecSmrg	}
12227e31ba66Smrg#endif
1223f7df2e56Smrg	return fd;
1224f7df2e56Smrg#else
1225f7df2e56Smrg        return -1;
1226f7df2e56Smrg#endif
1227f7df2e56Smrg}
1228f7df2e56Smrg
1229f7df2e56Smrgstatic int
1230f7df2e56SmrgProcShmCreateSegment(ClientPtr client)
1231f7df2e56Smrg{
1232f7df2e56Smrg    int fd;
1233f7df2e56Smrg    ShmDescPtr shmdesc;
1234f7df2e56Smrg    REQUEST(xShmCreateSegmentReq);
1235f7df2e56Smrg    xShmCreateSegmentReply rep = {
1236f7df2e56Smrg        .type = X_Reply,
1237f7df2e56Smrg        .nfd = 1,
1238f7df2e56Smrg        .sequenceNumber = client->sequence,
1239f7df2e56Smrg        .length = 0,
1240f7df2e56Smrg    };
1241f7df2e56Smrg
1242f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
12437e31ba66Smrg    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
1244f7df2e56Smrg    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1245f7df2e56Smrg        client->errorValue = stuff->readOnly;
1246f7df2e56Smrg        return BadValue;
124705b261ecSmrg    }
1248f7df2e56Smrg    fd = shm_tmpfile();
1249f7df2e56Smrg    if (fd < 0)
1250f7df2e56Smrg        return BadAlloc;
1251f7df2e56Smrg    if (ftruncate(fd, stuff->size) < 0) {
1252f7df2e56Smrg        close(fd);
1253f7df2e56Smrg        return BadAlloc;
1254f7df2e56Smrg    }
1255f7df2e56Smrg    shmdesc = malloc(sizeof(ShmDescRec));
1256f7df2e56Smrg    if (!shmdesc) {
1257f7df2e56Smrg        close(fd);
1258f7df2e56Smrg        return BadAlloc;
1259f7df2e56Smrg    }
1260f7df2e56Smrg    shmdesc->is_fd = TRUE;
1261f7df2e56Smrg    shmdesc->addr = mmap(NULL, stuff->size,
1262f7df2e56Smrg                         stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1263f7df2e56Smrg                         MAP_SHARED,
1264f7df2e56Smrg                         fd, 0);
1265f7df2e56Smrg
1266f7df2e56Smrg    if (shmdesc->addr == ((char *) -1)) {
1267f7df2e56Smrg        close(fd);
1268f7df2e56Smrg        free(shmdesc);
1269f7df2e56Smrg        return BadAccess;
1270f7df2e56Smrg    }
1271f7df2e56Smrg
1272f7df2e56Smrg    shmdesc->refcnt = 1;
1273f7df2e56Smrg    shmdesc->writable = !stuff->readOnly;
1274f7df2e56Smrg    shmdesc->size = stuff->size;
1275f7df2e56Smrg
1276f7df2e56Smrg    shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1277f7df2e56Smrg    if (!shmdesc->busfault) {
1278f7df2e56Smrg        close(fd);
1279f7df2e56Smrg        munmap(shmdesc->addr, shmdesc->size);
1280f7df2e56Smrg        free(shmdesc);
1281f7df2e56Smrg        return BadAlloc;
1282f7df2e56Smrg    }
1283f7df2e56Smrg
1284f7df2e56Smrg    shmdesc->next = Shmsegs;
1285f7df2e56Smrg    Shmsegs = shmdesc;
1286f7df2e56Smrg
1287f7df2e56Smrg    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc)) {
1288f7df2e56Smrg        close(fd);
1289f7df2e56Smrg        return BadAlloc;
1290f7df2e56Smrg    }
1291f7df2e56Smrg
1292f7df2e56Smrg    if (WriteFdToClient(client, fd, TRUE) < 0) {
1293f7df2e56Smrg        FreeResource(stuff->shmseg, RT_NONE);
1294f7df2e56Smrg        close(fd);
1295f7df2e56Smrg        return BadAlloc;
1296f7df2e56Smrg    }
1297f7df2e56Smrg    WriteToClient(client, sizeof (xShmCreateSegmentReply), &rep);
1298f7df2e56Smrg    return Success;
129905b261ecSmrg}
1300f7df2e56Smrg#endif /* SHM_FD_PASSING */
130105b261ecSmrg
130205b261ecSmrgstatic int
1303f7df2e56SmrgProcShmDispatch(ClientPtr client)
130405b261ecSmrg{
130505b261ecSmrg    REQUEST(xReq);
13067e31ba66Smrg
13077e31ba66Smrg    if (stuff->data == X_ShmQueryVersion)
1308f7df2e56Smrg        return ProcShmQueryVersion(client);
13097e31ba66Smrg
13107e31ba66Smrg    if (!client->local)
13117e31ba66Smrg        return BadRequest;
13127e31ba66Smrg
13137e31ba66Smrg    switch (stuff->data) {
131405b261ecSmrg    case X_ShmAttach:
1315f7df2e56Smrg        return ProcShmAttach(client);
131605b261ecSmrg    case X_ShmDetach:
1317f7df2e56Smrg        return ProcShmDetach(client);
131805b261ecSmrg    case X_ShmPutImage:
131905b261ecSmrg#ifdef PANORAMIX
1320f7df2e56Smrg        if (!noPanoramiXExtension)
1321f7df2e56Smrg            return ProcPanoramiXShmPutImage(client);
132205b261ecSmrg#endif
1323f7df2e56Smrg        return ProcShmPutImage(client);
132405b261ecSmrg    case X_ShmGetImage:
132505b261ecSmrg#ifdef PANORAMIX
1326f7df2e56Smrg        if (!noPanoramiXExtension)
1327f7df2e56Smrg            return ProcPanoramiXShmGetImage(client);
132805b261ecSmrg#endif
1329f7df2e56Smrg        return ProcShmGetImage(client);
133005b261ecSmrg    case X_ShmCreatePixmap:
133105b261ecSmrg#ifdef PANORAMIX
1332f7df2e56Smrg        if (!noPanoramiXExtension)
1333f7df2e56Smrg            return ProcPanoramiXShmCreatePixmap(client);
1334f7df2e56Smrg#endif
1335f7df2e56Smrg        return ProcShmCreatePixmap(client);
1336f7df2e56Smrg#ifdef SHM_FD_PASSING
1337f7df2e56Smrg    case X_ShmAttachFd:
1338f7df2e56Smrg        return ProcShmAttachFd(client);
1339f7df2e56Smrg    case X_ShmCreateSegment:
1340f7df2e56Smrg        return ProcShmCreateSegment(client);
134105b261ecSmrg#endif
134205b261ecSmrg    default:
1343f7df2e56Smrg        return BadRequest;
134405b261ecSmrg    }
134505b261ecSmrg}
134605b261ecSmrg
13477e31ba66Smrgstatic void _X_COLD
1348f7df2e56SmrgSShmCompletionEvent(xShmCompletionEvent * from, xShmCompletionEvent * to)
134905b261ecSmrg{
135005b261ecSmrg    to->type = from->type;
135105b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
135205b261ecSmrg    cpswapl(from->drawable, to->drawable);
135305b261ecSmrg    cpswaps(from->minorEvent, to->minorEvent);
135405b261ecSmrg    to->majorEvent = from->majorEvent;
135505b261ecSmrg    cpswapl(from->shmseg, to->shmseg);
135605b261ecSmrg    cpswapl(from->offset, to->offset);
135705b261ecSmrg}
135805b261ecSmrg
13597e31ba66Smrgstatic int _X_COLD
13604642e01fSmrgSProcShmQueryVersion(ClientPtr client)
136105b261ecSmrg{
136205b261ecSmrg    REQUEST(xShmQueryVersionReq);
136305b261ecSmrg
1364f7df2e56Smrg    swaps(&stuff->length);
136505b261ecSmrg    return ProcShmQueryVersion(client);
136605b261ecSmrg}
136705b261ecSmrg
13687e31ba66Smrgstatic int _X_COLD
13694642e01fSmrgSProcShmAttach(ClientPtr client)
137005b261ecSmrg{
137105b261ecSmrg    REQUEST(xShmAttachReq);
1372f7df2e56Smrg    swaps(&stuff->length);
137305b261ecSmrg    REQUEST_SIZE_MATCH(xShmAttachReq);
1374f7df2e56Smrg    swapl(&stuff->shmseg);
1375f7df2e56Smrg    swapl(&stuff->shmid);
137605b261ecSmrg    return ProcShmAttach(client);
137705b261ecSmrg}
137805b261ecSmrg
13797e31ba66Smrgstatic int _X_COLD
13804642e01fSmrgSProcShmDetach(ClientPtr client)
138105b261ecSmrg{
138205b261ecSmrg    REQUEST(xShmDetachReq);
1383f7df2e56Smrg    swaps(&stuff->length);
138405b261ecSmrg    REQUEST_SIZE_MATCH(xShmDetachReq);
1385f7df2e56Smrg    swapl(&stuff->shmseg);
138605b261ecSmrg    return ProcShmDetach(client);
138705b261ecSmrg}
138805b261ecSmrg
13897e31ba66Smrgstatic int _X_COLD
13904642e01fSmrgSProcShmPutImage(ClientPtr client)
139105b261ecSmrg{
139205b261ecSmrg    REQUEST(xShmPutImageReq);
1393f7df2e56Smrg    swaps(&stuff->length);
139405b261ecSmrg    REQUEST_SIZE_MATCH(xShmPutImageReq);
1395f7df2e56Smrg    swapl(&stuff->drawable);
1396f7df2e56Smrg    swapl(&stuff->gc);
1397f7df2e56Smrg    swaps(&stuff->totalWidth);
1398f7df2e56Smrg    swaps(&stuff->totalHeight);
1399f7df2e56Smrg    swaps(&stuff->srcX);
1400f7df2e56Smrg    swaps(&stuff->srcY);
1401f7df2e56Smrg    swaps(&stuff->srcWidth);
1402f7df2e56Smrg    swaps(&stuff->srcHeight);
1403f7df2e56Smrg    swaps(&stuff->dstX);
1404f7df2e56Smrg    swaps(&stuff->dstY);
1405f7df2e56Smrg    swapl(&stuff->shmseg);
1406f7df2e56Smrg    swapl(&stuff->offset);
140705b261ecSmrg    return ProcShmPutImage(client);
140805b261ecSmrg}
140905b261ecSmrg
14107e31ba66Smrgstatic int _X_COLD
14114642e01fSmrgSProcShmGetImage(ClientPtr client)
141205b261ecSmrg{
141305b261ecSmrg    REQUEST(xShmGetImageReq);
1414f7df2e56Smrg    swaps(&stuff->length);
141505b261ecSmrg    REQUEST_SIZE_MATCH(xShmGetImageReq);
1416f7df2e56Smrg    swapl(&stuff->drawable);
1417f7df2e56Smrg    swaps(&stuff->x);
1418f7df2e56Smrg    swaps(&stuff->y);
1419f7df2e56Smrg    swaps(&stuff->width);
1420f7df2e56Smrg    swaps(&stuff->height);
1421f7df2e56Smrg    swapl(&stuff->planeMask);
1422f7df2e56Smrg    swapl(&stuff->shmseg);
1423f7df2e56Smrg    swapl(&stuff->offset);
142405b261ecSmrg    return ProcShmGetImage(client);
142505b261ecSmrg}
142605b261ecSmrg
14277e31ba66Smrgstatic int _X_COLD
14284642e01fSmrgSProcShmCreatePixmap(ClientPtr client)
142905b261ecSmrg{
143005b261ecSmrg    REQUEST(xShmCreatePixmapReq);
1431f7df2e56Smrg    swaps(&stuff->length);
143205b261ecSmrg    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1433f7df2e56Smrg    swapl(&stuff->pid);
1434f7df2e56Smrg    swapl(&stuff->drawable);
1435f7df2e56Smrg    swaps(&stuff->width);
1436f7df2e56Smrg    swaps(&stuff->height);
1437f7df2e56Smrg    swapl(&stuff->shmseg);
1438f7df2e56Smrg    swapl(&stuff->offset);
143905b261ecSmrg    return ProcShmCreatePixmap(client);
144005b261ecSmrg}
144105b261ecSmrg
1442f7df2e56Smrg#ifdef SHM_FD_PASSING
14437e31ba66Smrgstatic int _X_COLD
1444f7df2e56SmrgSProcShmAttachFd(ClientPtr client)
1445f7df2e56Smrg{
1446f7df2e56Smrg    REQUEST(xShmAttachFdReq);
1447f7df2e56Smrg    SetReqFds(client, 1);
1448f7df2e56Smrg    swaps(&stuff->length);
1449f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmAttachFdReq);
1450f7df2e56Smrg    swapl(&stuff->shmseg);
1451f7df2e56Smrg    return ProcShmAttachFd(client);
1452f7df2e56Smrg}
1453f7df2e56Smrg
14547e31ba66Smrgstatic int _X_COLD
1455f7df2e56SmrgSProcShmCreateSegment(ClientPtr client)
1456f7df2e56Smrg{
1457f7df2e56Smrg    REQUEST(xShmCreateSegmentReq);
1458f7df2e56Smrg    swaps(&stuff->length);
1459f7df2e56Smrg    REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
1460f7df2e56Smrg    swapl(&stuff->shmseg);
1461f7df2e56Smrg    swapl(&stuff->size);
1462f7df2e56Smrg    return ProcShmCreateSegment(client);
1463f7df2e56Smrg}
1464f7df2e56Smrg#endif  /* SHM_FD_PASSING */
1465f7df2e56Smrg
14667e31ba66Smrgstatic int _X_COLD
1467f7df2e56SmrgSProcShmDispatch(ClientPtr client)
146805b261ecSmrg{
146905b261ecSmrg    REQUEST(xReq);
14707e31ba66Smrg
14717e31ba66Smrg    if (stuff->data == X_ShmQueryVersion)
1472f7df2e56Smrg        return SProcShmQueryVersion(client);
14737e31ba66Smrg
14747e31ba66Smrg    if (!client->local)
14757e31ba66Smrg        return BadRequest;
14767e31ba66Smrg
14777e31ba66Smrg    switch (stuff->data) {
147805b261ecSmrg    case X_ShmAttach:
1479f7df2e56Smrg        return SProcShmAttach(client);
148005b261ecSmrg    case X_ShmDetach:
1481f7df2e56Smrg        return SProcShmDetach(client);
148205b261ecSmrg    case X_ShmPutImage:
1483f7df2e56Smrg        return SProcShmPutImage(client);
148405b261ecSmrg    case X_ShmGetImage:
1485f7df2e56Smrg        return SProcShmGetImage(client);
148605b261ecSmrg    case X_ShmCreatePixmap:
1487f7df2e56Smrg        return SProcShmCreatePixmap(client);
1488f7df2e56Smrg#ifdef SHM_FD_PASSING
1489f7df2e56Smrg    case X_ShmAttachFd:
1490f7df2e56Smrg        return SProcShmAttachFd(client);
1491f7df2e56Smrg    case X_ShmCreateSegment:
1492f7df2e56Smrg        return SProcShmCreateSegment(client);
1493f7df2e56Smrg#endif
149405b261ecSmrg    default:
1495f7df2e56Smrg        return BadRequest;
149605b261ecSmrg    }
149705b261ecSmrg}
149865b04b38Smrg
149965b04b38Smrgvoid
1500f7df2e56SmrgShmExtensionInit(void)
150165b04b38Smrg{
150265b04b38Smrg    ExtensionEntry *extEntry;
150365b04b38Smrg    int i;
150465b04b38Smrg
150565b04b38Smrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL
1506f7df2e56Smrg    if (!CheckForShmSyscall()) {
1507f7df2e56Smrg        ErrorF("MIT-SHM extension disabled due to lack of kernel support\n");
1508f7df2e56Smrg        return;
150965b04b38Smrg    }
151065b04b38Smrg#endif
151165b04b38Smrg
151265b04b38Smrg    if (!ShmRegisterPrivates())
1513f7df2e56Smrg        return;
151465b04b38Smrg
151565b04b38Smrg    sharedPixmaps = xFalse;
151665b04b38Smrg    {
1517f7df2e56Smrg        sharedPixmaps = xTrue;
1518f7df2e56Smrg        for (i = 0; i < screenInfo.numScreens; i++) {
1519f7df2e56Smrg            ShmScrPrivateRec *screen_priv =
1520f7df2e56Smrg                ShmInitScreenPriv(screenInfo.screens[i]);
1521f7df2e56Smrg            if (!screen_priv->shmFuncs)
1522f7df2e56Smrg                screen_priv->shmFuncs = &miFuncs;
1523f7df2e56Smrg            if (!screen_priv->shmFuncs->CreatePixmap)
1524f7df2e56Smrg                sharedPixmaps = xFalse;
1525f7df2e56Smrg        }
1526f7df2e56Smrg        if (sharedPixmaps)
1527f7df2e56Smrg            for (i = 0; i < screenInfo.numScreens; i++) {
1528f7df2e56Smrg                ShmScrPrivateRec *screen_priv =
1529f7df2e56Smrg                    ShmGetScreenPriv(screenInfo.screens[i]);
1530f7df2e56Smrg                screen_priv->destroyPixmap =
1531f7df2e56Smrg                    screenInfo.screens[i]->DestroyPixmap;
1532f7df2e56Smrg                screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap;
1533f7df2e56Smrg            }
153465b04b38Smrg    }
153565b04b38Smrg    ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg");
153665b04b38Smrg    if (ShmSegType &&
1537f7df2e56Smrg        (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors,
1538f7df2e56Smrg                                 ProcShmDispatch, SProcShmDispatch,
1539f7df2e56Smrg                                 ShmResetProc, StandardMinorOpcode))) {
1540f7df2e56Smrg        ShmReqCode = (unsigned char) extEntry->base;
1541f7df2e56Smrg        ShmCompletionCode = extEntry->eventBase;
1542f7df2e56Smrg        BadShmSegCode = extEntry->errorBase;
1543f7df2e56Smrg        SetResourceTypeErrorValue(ShmSegType, BadShmSegCode);
1544f7df2e56Smrg        EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent;
154565b04b38Smrg    }
154665b04b38Smrg}
1547