shm.c revision 4e185dc0
1/************************************************************
2
3Copyright 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25********************************************************/
26
27/* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */
28
29#define SHM
30
31#ifdef HAVE_DIX_CONFIG_H
32#include <dix-config.h>
33#endif
34
35#include <sys/types.h>
36#include <sys/ipc.h>
37#include <sys/shm.h>
38#ifdef HAVE_MEMFD_CREATE
39#include <sys/mman.h>
40#endif
41#include <unistd.h>
42#include <sys/stat.h>
43#include <fcntl.h>
44#include <X11/X.h>
45#include <X11/Xproto.h>
46#include "misc.h"
47#include "os.h"
48#include "dixstruct.h"
49#include "resource.h"
50#include "scrnintstr.h"
51#include "windowstr.h"
52#include "pixmapstr.h"
53#include "gcstruct.h"
54#include "extnsionst.h"
55#include "servermd.h"
56#include "shmint.h"
57#include "xace.h"
58#include <X11/extensions/shmproto.h>
59#include <X11/Xfuncproto.h>
60#include <sys/mman.h>
61#include "protocol-versions.h"
62#include "busfault.h"
63
64/* Needed for Solaris cross-zone shared memory extension */
65#ifdef HAVE_SHMCTL64
66#include <sys/ipc_impl.h>
67#define SHMSTAT(id, buf)	shmctl64(id, IPC_STAT64, buf)
68#define SHMSTAT_TYPE 		struct shmid_ds64
69#define SHMPERM_TYPE 		struct ipc_perm64
70#define SHM_PERM(buf) 		buf.shmx_perm
71#define SHM_SEGSZ(buf)		buf.shmx_segsz
72#define SHMPERM_UID(p)		p->ipcx_uid
73#define SHMPERM_CUID(p)		p->ipcx_cuid
74#define SHMPERM_GID(p)		p->ipcx_gid
75#define SHMPERM_CGID(p)		p->ipcx_cgid
76#define SHMPERM_MODE(p)		p->ipcx_mode
77#define SHMPERM_ZONEID(p)	p->ipcx_zoneid
78#else
79#define SHMSTAT(id, buf) 	shmctl(id, IPC_STAT, buf)
80#define SHMSTAT_TYPE 		struct shmid_ds
81#define SHMPERM_TYPE 		struct ipc_perm
82#define SHM_PERM(buf) 		buf.shm_perm
83#define SHM_SEGSZ(buf)		buf.shm_segsz
84#define SHMPERM_UID(p)		p->uid
85#define SHMPERM_CUID(p)		p->cuid
86#define SHMPERM_GID(p)		p->gid
87#define SHMPERM_CGID(p)		p->cgid
88#define SHMPERM_MODE(p)		p->mode
89#endif
90
91#ifdef PANORAMIX
92#include "panoramiX.h"
93#include "panoramiXsrv.h"
94#endif
95
96#include "extinit.h"
97
98typedef struct _ShmScrPrivateRec {
99    CloseScreenProcPtr CloseScreen;
100    ShmFuncsPtr shmFuncs;
101    DestroyPixmapProcPtr destroyPixmap;
102} ShmScrPrivateRec;
103
104static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS);
105static int ShmDetachSegment(void *value, XID shmseg);
106static void ShmResetProc(ExtensionEntry *extEntry);
107static void SShmCompletionEvent(xShmCompletionEvent *from,
108                                xShmCompletionEvent *to);
109
110static Bool ShmDestroyPixmap(PixmapPtr pPixmap);
111
112static unsigned char ShmReqCode;
113int ShmCompletionCode;
114int BadShmSegCode;
115RESTYPE ShmSegType;
116static ShmDescPtr Shmsegs;
117static Bool sharedPixmaps;
118static DevPrivateKeyRec shmScrPrivateKeyRec;
119
120#define shmScrPrivateKey (&shmScrPrivateKeyRec)
121static DevPrivateKeyRec shmPixmapPrivateKeyRec;
122
123#define shmPixmapPrivateKey (&shmPixmapPrivateKeyRec)
124static ShmFuncs miFuncs = { NULL, NULL };
125static ShmFuncs fbFuncs = { fbShmCreatePixmap, NULL };
126
127#define ShmGetScreenPriv(s) ((ShmScrPrivateRec *)dixLookupPrivate(&(s)->devPrivates, shmScrPrivateKey))
128
129#define VERIFY_SHMSEG(shmseg,shmdesc,client) \
130{ \
131    int tmprc; \
132    tmprc = dixLookupResourceByType((void **)&(shmdesc), shmseg, ShmSegType, \
133                                    client, DixReadAccess); \
134    if (tmprc != Success) \
135	return tmprc; \
136}
137
138#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \
139{ \
140    VERIFY_SHMSEG(shmseg, shmdesc, client); \
141    if ((offset & 3) || (offset > shmdesc->size)) \
142    { \
143	client->errorValue = offset; \
144	return BadValue; \
145    } \
146    if (needwrite && !shmdesc->writable) \
147	return BadAccess; \
148}
149
150#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \
151{ \
152    if ((offset + len) > shmdesc->size) \
153    { \
154	return BadAccess; \
155    } \
156}
157
158#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
159
160static Bool badSysCall = FALSE;
161
162static void
163SigSysHandler(int signo)
164{
165    badSysCall = TRUE;
166}
167
168static Bool
169CheckForShmSyscall(void)
170{
171    void (*oldHandler) (int);
172    int shmid = -1;
173
174    /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
175    oldHandler = OsSignal(SIGSYS, SigSysHandler);
176
177    badSysCall = FALSE;
178    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
179
180    if (shmid != -1) {
181        /* Successful allocation - clean up */
182        shmctl(shmid, IPC_RMID, NULL);
183    }
184    else {
185        /* Allocation failed */
186        badSysCall = TRUE;
187    }
188    OsSignal(SIGSYS, oldHandler);
189    return !badSysCall;
190}
191
192#define MUST_CHECK_FOR_SHM_SYSCALL
193
194#endif
195
196static Bool
197ShmCloseScreen(ScreenPtr pScreen)
198{
199    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
200
201    pScreen->CloseScreen = screen_priv->CloseScreen;
202    dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL);
203    free(screen_priv);
204    return (*pScreen->CloseScreen) (pScreen);
205}
206
207static ShmScrPrivateRec *
208ShmInitScreenPriv(ScreenPtr pScreen)
209{
210    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
211
212    if (!screen_priv) {
213        screen_priv = calloc(1, sizeof(ShmScrPrivateRec));
214        screen_priv->CloseScreen = pScreen->CloseScreen;
215        dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv);
216        pScreen->CloseScreen = ShmCloseScreen;
217    }
218    return screen_priv;
219}
220
221static Bool
222ShmRegisterPrivates(void)
223{
224    if (!dixRegisterPrivateKey(&shmScrPrivateKeyRec, PRIVATE_SCREEN, 0))
225        return FALSE;
226    if (!dixRegisterPrivateKey(&shmPixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
227        return FALSE;
228    return TRUE;
229}
230
231 /*ARGSUSED*/ static void
232ShmResetProc(ExtensionEntry * extEntry)
233{
234    int i;
235
236    for (i = 0; i < screenInfo.numScreens; i++)
237        ShmRegisterFuncs(screenInfo.screens[i], NULL);
238}
239
240void
241ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs)
242{
243    if (!ShmRegisterPrivates())
244        return;
245    ShmInitScreenPriv(pScreen)->shmFuncs = funcs;
246}
247
248static Bool
249ShmDestroyPixmap(PixmapPtr pPixmap)
250{
251    ScreenPtr pScreen = pPixmap->drawable.pScreen;
252    ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
253    void *shmdesc = NULL;
254    Bool ret;
255
256    if (pPixmap->refcnt == 1)
257        shmdesc = dixLookupPrivate(&pPixmap->devPrivates, shmPixmapPrivateKey);
258
259    pScreen->DestroyPixmap = screen_priv->destroyPixmap;
260    ret = (*pScreen->DestroyPixmap) (pPixmap);
261    screen_priv->destroyPixmap = pScreen->DestroyPixmap;
262    pScreen->DestroyPixmap = ShmDestroyPixmap;
263
264    if (shmdesc)
265	ShmDetachSegment(shmdesc, 0);
266
267    return ret;
268}
269
270void
271ShmRegisterFbFuncs(ScreenPtr pScreen)
272{
273    ShmRegisterFuncs(pScreen, &fbFuncs);
274}
275
276static int
277ProcShmQueryVersion(ClientPtr client)
278{
279    xShmQueryVersionReply rep = {
280        .type = X_Reply,
281        .sharedPixmaps = sharedPixmaps,
282        .sequenceNumber = client->sequence,
283        .length = 0,
284        .majorVersion = SERVER_SHM_MAJOR_VERSION,
285        .minorVersion = SERVER_SHM_MINOR_VERSION,
286        .uid = geteuid(),
287        .gid = getegid(),
288        .pixmapFormat = sharedPixmaps ? ZPixmap : 0
289    };
290
291    REQUEST_SIZE_MATCH(xShmQueryVersionReq);
292
293    if (client->swapped) {
294        swaps(&rep.sequenceNumber);
295        swapl(&rep.length);
296        swaps(&rep.majorVersion);
297        swaps(&rep.minorVersion);
298        swaps(&rep.uid);
299        swaps(&rep.gid);
300    }
301    WriteToClient(client, sizeof(xShmQueryVersionReply), &rep);
302    return Success;
303}
304
305/*
306 * Simulate the access() system call for a shared memory segement,
307 * using the credentials from the client if available
308 */
309static int
310shm_access(ClientPtr client, SHMPERM_TYPE * perm, int readonly)
311{
312    int uid, gid;
313    mode_t mask;
314    int uidset = 0, gidset = 0;
315    LocalClientCredRec *lcc;
316
317    if (GetLocalClientCreds(client, &lcc) != -1) {
318
319        if (lcc->fieldsSet & LCC_UID_SET) {
320            uid = lcc->euid;
321            uidset = 1;
322        }
323        if (lcc->fieldsSet & LCC_GID_SET) {
324            gid = lcc->egid;
325            gidset = 1;
326        }
327
328#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID)
329        if (((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1)
330            || (lcc->zoneid != SHMPERM_ZONEID(perm))) {
331            uidset = 0;
332            gidset = 0;
333        }
334#endif
335        FreeLocalClientCreds(lcc);
336
337        if (uidset) {
338            /* User id 0 always gets access */
339            if (uid == 0) {
340                return 0;
341            }
342            /* Check the owner */
343            if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) {
344                mask = S_IRUSR;
345                if (!readonly) {
346                    mask |= S_IWUSR;
347                }
348                return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
349            }
350        }
351
352        if (gidset) {
353            /* Check the group */
354            if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) {
355                mask = S_IRGRP;
356                if (!readonly) {
357                    mask |= S_IWGRP;
358                }
359                return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
360            }
361        }
362    }
363    /* Otherwise, check everyone else */
364    mask = S_IROTH;
365    if (!readonly) {
366        mask |= S_IWOTH;
367    }
368    return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
369}
370
371static int
372ProcShmAttach(ClientPtr client)
373{
374    SHMSTAT_TYPE buf;
375    ShmDescPtr shmdesc;
376
377    REQUEST(xShmAttachReq);
378
379    REQUEST_SIZE_MATCH(xShmAttachReq);
380    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
381    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
382        client->errorValue = stuff->readOnly;
383        return BadValue;
384    }
385    for (shmdesc = Shmsegs; shmdesc; shmdesc = shmdesc->next) {
386        if (!SHMDESC_IS_FD(shmdesc) && shmdesc->shmid == stuff->shmid)
387            break;
388    }
389    if (shmdesc) {
390        if (!stuff->readOnly && !shmdesc->writable)
391            return BadAccess;
392        shmdesc->refcnt++;
393    }
394    else {
395        shmdesc = malloc(sizeof(ShmDescRec));
396        if (!shmdesc)
397            return BadAlloc;
398#ifdef SHM_FD_PASSING
399        shmdesc->is_fd = FALSE;
400#endif
401        shmdesc->addr = shmat(stuff->shmid, 0,
402                              stuff->readOnly ? SHM_RDONLY : 0);
403        if ((shmdesc->addr == ((char *) -1)) || SHMSTAT(stuff->shmid, &buf)) {
404            free(shmdesc);
405            return BadAccess;
406        }
407
408        /* The attach was performed with root privs. We must
409         * do manual checking of access rights for the credentials
410         * of the client */
411
412        if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) {
413            shmdt(shmdesc->addr);
414            free(shmdesc);
415            return BadAccess;
416        }
417
418        shmdesc->shmid = stuff->shmid;
419        shmdesc->refcnt = 1;
420        shmdesc->writable = !stuff->readOnly;
421        shmdesc->size = SHM_SEGSZ(buf);
422        shmdesc->next = Shmsegs;
423        Shmsegs = shmdesc;
424    }
425    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
426        return BadAlloc;
427    return Success;
428}
429
430 /*ARGSUSED*/ static int
431ShmDetachSegment(void *value, /* must conform to DeleteType */
432                 XID unused)
433{
434    ShmDescPtr shmdesc = (ShmDescPtr) value;
435    ShmDescPtr *prev;
436
437    if (--shmdesc->refcnt)
438        return TRUE;
439#if SHM_FD_PASSING
440    if (shmdesc->is_fd) {
441        if (shmdesc->busfault)
442            busfault_unregister(shmdesc->busfault);
443        munmap(shmdesc->addr, shmdesc->size);
444    } else
445#endif
446        shmdt(shmdesc->addr);
447    for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next);
448    *prev = shmdesc->next;
449    free(shmdesc);
450    return Success;
451}
452
453static int
454ProcShmDetach(ClientPtr client)
455{
456    ShmDescPtr shmdesc;
457
458    REQUEST(xShmDetachReq);
459
460    REQUEST_SIZE_MATCH(xShmDetachReq);
461    VERIFY_SHMSEG(stuff->shmseg, shmdesc, client);
462    FreeResource(stuff->shmseg, RT_NONE);
463    return Success;
464}
465
466/*
467 * If the given request doesn't exactly match PutImage's constraints,
468 * wrap the image in a scratch pixmap header and let CopyArea sort it out.
469 */
470static void
471doShmPutImage(DrawablePtr dst, GCPtr pGC,
472              int depth, unsigned int format,
473              int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
474              char *data)
475{
476    PixmapPtr pPixmap;
477
478    if (format == ZPixmap || (format == XYPixmap && depth == 1)) {
479        pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth,
480                                         BitsPerPixel(depth),
481                                         PixmapBytePad(w, depth), data);
482        if (!pPixmap)
483            return;
484        pGC->ops->CopyArea((DrawablePtr) pPixmap, dst, pGC, sx, sy, sw, sh, dx,
485                           dy);
486        FreeScratchPixmapHeader(pPixmap);
487    }
488    else {
489        GCPtr putGC = GetScratchGC(depth, dst->pScreen);
490
491        if (!putGC)
492            return;
493
494        pPixmap = (*dst->pScreen->CreatePixmap) (dst->pScreen, sw, sh, depth,
495                                                 CREATE_PIXMAP_USAGE_SCRATCH);
496        if (!pPixmap) {
497            FreeScratchGC(putGC);
498            return;
499        }
500        ValidateGC(&pPixmap->drawable, putGC);
501        (*putGC->ops->PutImage) (&pPixmap->drawable, putGC, depth, -sx, -sy, w,
502                                 h, 0,
503                                 (format == XYPixmap) ? XYPixmap : ZPixmap,
504                                 data);
505        FreeScratchGC(putGC);
506        if (format == XYBitmap)
507            (void) (*pGC->ops->CopyPlane) (&pPixmap->drawable, dst, pGC, 0, 0,
508                                           sw, sh, dx, dy, 1L);
509        else
510            (void) (*pGC->ops->CopyArea) (&pPixmap->drawable, dst, pGC, 0, 0,
511                                          sw, sh, dx, dy);
512        (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap);
513    }
514}
515
516static int
517ProcShmPutImage(ClientPtr client)
518{
519    GCPtr pGC;
520    DrawablePtr pDraw;
521    long length;
522    ShmDescPtr shmdesc;
523
524    REQUEST(xShmPutImageReq);
525
526    REQUEST_SIZE_MATCH(xShmPutImageReq);
527    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
528    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client);
529    if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse))
530        return BadValue;
531    if (stuff->format == XYBitmap) {
532        if (stuff->depth != 1)
533            return BadMatch;
534        length = PixmapBytePad(stuff->totalWidth, 1);
535    }
536    else if (stuff->format == XYPixmap) {
537        if (pDraw->depth != stuff->depth)
538            return BadMatch;
539        length = PixmapBytePad(stuff->totalWidth, 1);
540        length *= stuff->depth;
541    }
542    else if (stuff->format == ZPixmap) {
543        if (pDraw->depth != stuff->depth)
544            return BadMatch;
545        length = PixmapBytePad(stuff->totalWidth, stuff->depth);
546    }
547    else {
548        client->errorValue = stuff->format;
549        return BadValue;
550    }
551
552    /*
553     * There's a potential integer overflow in this check:
554     * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight,
555     *                client);
556     * the version below ought to avoid it
557     */
558    if (stuff->totalHeight != 0 &&
559        length > (shmdesc->size - stuff->offset) / stuff->totalHeight) {
560        client->errorValue = stuff->totalWidth;
561        return BadValue;
562    }
563    if (stuff->srcX > stuff->totalWidth) {
564        client->errorValue = stuff->srcX;
565        return BadValue;
566    }
567    if (stuff->srcY > stuff->totalHeight) {
568        client->errorValue = stuff->srcY;
569        return BadValue;
570    }
571    if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) {
572        client->errorValue = stuff->srcWidth;
573        return BadValue;
574    }
575    if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) {
576        client->errorValue = stuff->srcHeight;
577        return BadValue;
578    }
579
580    if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) ||
581         ((stuff->format != ZPixmap) &&
582          (stuff->srcX < screenInfo.bitmapScanlinePad) &&
583          ((stuff->format == XYBitmap) ||
584           ((stuff->srcY == 0) &&
585            (stuff->srcHeight == stuff->totalHeight))))) &&
586        ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth))
587        (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth,
588                               stuff->dstX, stuff->dstY,
589                               stuff->totalWidth, stuff->srcHeight,
590                               stuff->srcX, stuff->format,
591                               shmdesc->addr + stuff->offset +
592                               (stuff->srcY * length));
593    else
594        doShmPutImage(pDraw, pGC, stuff->depth, stuff->format,
595                      stuff->totalWidth, stuff->totalHeight,
596                      stuff->srcX, stuff->srcY,
597                      stuff->srcWidth, stuff->srcHeight,
598                      stuff->dstX, stuff->dstY, shmdesc->addr + stuff->offset);
599
600    if (stuff->sendEvent) {
601        xShmCompletionEvent ev = {
602            .type = ShmCompletionCode,
603            .drawable = stuff->drawable,
604            .minorEvent = X_ShmPutImage,
605            .majorEvent = ShmReqCode,
606            .shmseg = stuff->shmseg,
607            .offset = stuff->offset
608        };
609        WriteEventsToClient(client, 1, (xEvent *) &ev);
610    }
611
612    return Success;
613}
614
615static int
616ProcShmGetImage(ClientPtr client)
617{
618    DrawablePtr pDraw;
619    long lenPer = 0, length;
620    Mask plane = 0;
621    xShmGetImageReply xgi;
622    ShmDescPtr shmdesc;
623    VisualID visual = None;
624    RegionPtr pVisibleRegion = NULL;
625    int rc;
626
627    REQUEST(xShmGetImageReq);
628
629    REQUEST_SIZE_MATCH(xShmGetImageReq);
630    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
631        client->errorValue = stuff->format;
632        return BadValue;
633    }
634    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
635    if (rc != Success)
636        return rc;
637    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
638    if (pDraw->type == DRAWABLE_WINDOW) {
639        if (   /* check for being viewable */
640               !((WindowPtr) pDraw)->realized ||
641               /* check for being on screen */
642               pDraw->x + stuff->x < 0 ||
643               pDraw->x + stuff->x + (int) stuff->width > pDraw->pScreen->width
644               || pDraw->y + stuff->y < 0 ||
645               pDraw->y + stuff->y + (int) stuff->height >
646               pDraw->pScreen->height ||
647               /* check for being inside of border */
648               stuff->x < -wBorderWidth((WindowPtr) pDraw) ||
649               stuff->x + (int) stuff->width >
650               wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
651               stuff->y < -wBorderWidth((WindowPtr) pDraw) ||
652               stuff->y + (int) stuff->height >
653               wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
654            return BadMatch;
655        visual = wVisual(((WindowPtr) pDraw));
656        if (pDraw->type == DRAWABLE_WINDOW)
657            pVisibleRegion = &((WindowPtr) pDraw)->borderClip;
658        pDraw->pScreen->SourceValidate(pDraw, stuff->x, stuff->y,
659                                       stuff->width, stuff->height,
660                                       IncludeInferiors);
661    }
662    else {
663        if (stuff->x < 0 ||
664            stuff->x + (int) stuff->width > pDraw->width ||
665            stuff->y < 0 || stuff->y + (int) stuff->height > pDraw->height)
666            return BadMatch;
667        visual = None;
668    }
669    xgi = (xShmGetImageReply) {
670        .type = X_Reply,
671        .sequenceNumber = client->sequence,
672        .length = 0,
673        .visual = visual,
674        .depth = pDraw->depth
675    };
676    if (stuff->format == ZPixmap) {
677        length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height;
678    }
679    else {
680        lenPer = PixmapBytePad(stuff->width, 1) * stuff->height;
681        plane = ((Mask) 1) << (pDraw->depth - 1);
682        /* only planes asked for */
683        length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
684    }
685
686    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
687    xgi.size = length;
688
689    if (length == 0) {
690        /* nothing to do */
691    }
692    else if (stuff->format == ZPixmap) {
693        (*pDraw->pScreen->GetImage) (pDraw, stuff->x, stuff->y,
694                                     stuff->width, stuff->height,
695                                     stuff->format, stuff->planeMask,
696                                     shmdesc->addr + stuff->offset);
697        if (pVisibleRegion)
698            XaceCensorImage(client, pVisibleRegion,
699                    PixmapBytePad(stuff->width, pDraw->depth), pDraw,
700                    stuff->x, stuff->y, stuff->width, stuff->height,
701                    stuff->format, shmdesc->addr + stuff->offset);
702    }
703    else {
704
705        length = stuff->offset;
706        for (; plane; plane >>= 1) {
707            if (stuff->planeMask & plane) {
708                (*pDraw->pScreen->GetImage) (pDraw,
709                                             stuff->x, stuff->y,
710                                             stuff->width, stuff->height,
711                                             stuff->format, plane,
712                                             shmdesc->addr + length);
713                if (pVisibleRegion)
714                    XaceCensorImage(client, pVisibleRegion,
715                            BitmapBytePad(stuff->width), pDraw,
716                            stuff->x, stuff->y, stuff->width, stuff->height,
717                            stuff->format, shmdesc->addr + length);
718                length += lenPer;
719            }
720        }
721    }
722
723    if (client->swapped) {
724        swaps(&xgi.sequenceNumber);
725        swapl(&xgi.length);
726        swapl(&xgi.visual);
727        swapl(&xgi.size);
728    }
729    WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
730
731    return Success;
732}
733
734#ifdef PANORAMIX
735static int
736ProcPanoramiXShmPutImage(ClientPtr client)
737{
738    int j, result, orig_x, orig_y;
739    PanoramiXRes *draw, *gc;
740    Bool sendEvent, isRoot;
741
742    REQUEST(xShmPutImageReq);
743    REQUEST_SIZE_MATCH(xShmPutImageReq);
744
745    result = dixLookupResourceByClass((void **) &draw, stuff->drawable,
746                                      XRC_DRAWABLE, client, DixWriteAccess);
747    if (result != Success)
748        return (result == BadValue) ? BadDrawable : result;
749
750    result = dixLookupResourceByType((void **) &gc, stuff->gc,
751                                     XRT_GC, client, DixReadAccess);
752    if (result != Success)
753        return result;
754
755    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
756
757    orig_x = stuff->dstX;
758    orig_y = stuff->dstY;
759    sendEvent = stuff->sendEvent;
760    stuff->sendEvent = 0;
761    FOR_NSCREENS(j) {
762        if (!j)
763            stuff->sendEvent = sendEvent;
764        stuff->drawable = draw->info[j].id;
765        stuff->gc = gc->info[j].id;
766        if (isRoot) {
767            stuff->dstX = orig_x - screenInfo.screens[j]->x;
768            stuff->dstY = orig_y - screenInfo.screens[j]->y;
769        }
770        result = ProcShmPutImage(client);
771        if (result != Success)
772            break;
773    }
774    return result;
775}
776
777static int
778ProcPanoramiXShmGetImage(ClientPtr client)
779{
780    PanoramiXRes *draw;
781    DrawablePtr *drawables;
782    DrawablePtr pDraw;
783    xShmGetImageReply xgi;
784    ShmDescPtr shmdesc;
785    int i, x, y, w, h, format, rc;
786    Mask plane = 0, planemask;
787    long lenPer = 0, length, widthBytesLine;
788    Bool isRoot;
789
790    REQUEST(xShmGetImageReq);
791
792    REQUEST_SIZE_MATCH(xShmGetImageReq);
793
794    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
795        client->errorValue = stuff->format;
796        return BadValue;
797    }
798
799    rc = dixLookupResourceByClass((void **) &draw, stuff->drawable,
800                                  XRC_DRAWABLE, client, DixWriteAccess);
801    if (rc != Success)
802        return (rc == BadValue) ? BadDrawable : rc;
803
804    if (draw->type == XRT_PIXMAP)
805        return ProcShmGetImage(client);
806
807    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
808    if (rc != Success)
809        return rc;
810
811    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
812
813    x = stuff->x;
814    y = stuff->y;
815    w = stuff->width;
816    h = stuff->height;
817    format = stuff->format;
818    planemask = stuff->planeMask;
819
820    isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
821
822    if (isRoot) {
823        if (                    /* check for being onscreen */
824               x < 0 || x + w > PanoramiXPixWidth ||
825               y < 0 || y + h > PanoramiXPixHeight)
826            return BadMatch;
827    }
828    else {
829        if (                    /* check for being onscreen */
830               screenInfo.screens[0]->x + pDraw->x + x < 0 ||
831               screenInfo.screens[0]->x + pDraw->x + x + w > PanoramiXPixWidth
832               || screenInfo.screens[0]->y + pDraw->y + y < 0 ||
833               screenInfo.screens[0]->y + pDraw->y + y + h > PanoramiXPixHeight
834               ||
835               /* check for being inside of border */
836               x < -wBorderWidth((WindowPtr) pDraw) ||
837               x + w > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
838               y < -wBorderWidth((WindowPtr) pDraw) ||
839               y + h > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
840            return BadMatch;
841    }
842
843    if (format == ZPixmap) {
844        widthBytesLine = PixmapBytePad(w, pDraw->depth);
845        length = widthBytesLine * h;
846    }
847    else {
848        widthBytesLine = PixmapBytePad(w, 1);
849        lenPer = widthBytesLine * h;
850        plane = ((Mask) 1) << (pDraw->depth - 1);
851        length = lenPer * Ones(planemask & (plane | (plane - 1)));
852    }
853
854    VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
855
856    drawables = calloc(PanoramiXNumScreens, sizeof(DrawablePtr));
857    if (!drawables)
858        return BadAlloc;
859
860    drawables[0] = pDraw;
861    FOR_NSCREENS_FORWARD_SKIP(i) {
862        rc = dixLookupDrawable(drawables + i, draw->info[i].id, client, 0,
863                               DixReadAccess);
864        if (rc != Success) {
865            free(drawables);
866            return rc;
867        }
868    }
869    FOR_NSCREENS_FORWARD(i) {
870        drawables[i]->pScreen->SourceValidate(drawables[i], 0, 0,
871                                              drawables[i]->width,
872                                              drawables[i]->height,
873                                              IncludeInferiors);
874    }
875
876    xgi = (xShmGetImageReply) {
877        .type = X_Reply,
878        .sequenceNumber = client->sequence,
879        .length = 0,
880        .visual = wVisual(((WindowPtr) pDraw)),
881        .depth = pDraw->depth
882    };
883
884    xgi.size = length;
885
886    if (length == 0) {          /* nothing to do */
887    }
888    else if (format == ZPixmap) {
889        XineramaGetImageData(drawables, x, y, w, h, format, planemask,
890                             shmdesc->addr + stuff->offset,
891                             widthBytesLine, isRoot);
892    }
893    else {
894
895        length = stuff->offset;
896        for (; plane; plane >>= 1) {
897            if (planemask & plane) {
898                XineramaGetImageData(drawables, x, y, w, h,
899                                     format, plane, shmdesc->addr + length,
900                                     widthBytesLine, isRoot);
901                length += lenPer;
902            }
903        }
904    }
905    free(drawables);
906
907    if (client->swapped) {
908        swaps(&xgi.sequenceNumber);
909        swapl(&xgi.length);
910        swapl(&xgi.visual);
911        swapl(&xgi.size);
912    }
913    WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
914
915    return Success;
916}
917
918static int
919ProcPanoramiXShmCreatePixmap(ClientPtr client)
920{
921    ScreenPtr pScreen = NULL;
922    PixmapPtr pMap = NULL;
923    DrawablePtr pDraw;
924    DepthPtr pDepth;
925    int i, j, result, rc;
926    ShmDescPtr shmdesc;
927
928    REQUEST(xShmCreatePixmapReq);
929    unsigned int width, height, depth;
930    unsigned long size;
931    PanoramiXRes *newPix;
932
933    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
934    client->errorValue = stuff->pid;
935    if (!sharedPixmaps)
936        return BadImplementation;
937    LEGAL_NEW_RESOURCE(stuff->pid, client);
938    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
939                           DixGetAttrAccess);
940    if (rc != Success)
941        return rc;
942
943    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
944
945    width = stuff->width;
946    height = stuff->height;
947    depth = stuff->depth;
948    if (!width || !height || !depth) {
949        client->errorValue = 0;
950        return BadValue;
951    }
952    if (width > 32767 || height > 32767)
953        return BadAlloc;
954
955    if (stuff->depth != 1) {
956        pDepth = pDraw->pScreen->allowedDepths;
957        for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
958            if (pDepth->depth == stuff->depth)
959                goto CreatePmap;
960        client->errorValue = stuff->depth;
961        return BadValue;
962    }
963
964 CreatePmap:
965    size = PixmapBytePad(width, depth) * height;
966    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
967        if (size < width * height)
968            return BadAlloc;
969    }
970    /* thankfully, offset is unsigned */
971    if (stuff->offset + size < size)
972        return BadAlloc;
973
974    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
975
976    if (!(newPix = malloc(sizeof(PanoramiXRes))))
977        return BadAlloc;
978
979    newPix->type = XRT_PIXMAP;
980    newPix->u.pix.shared = TRUE;
981    panoramix_setup_ids(newPix, client, stuff->pid);
982
983    result = Success;
984
985    FOR_NSCREENS(j) {
986        ShmScrPrivateRec *screen_priv;
987
988        pScreen = screenInfo.screens[j];
989
990        screen_priv = ShmGetScreenPriv(pScreen);
991        pMap = (*screen_priv->shmFuncs->CreatePixmap) (pScreen,
992                                                       stuff->width,
993                                                       stuff->height,
994                                                       stuff->depth,
995                                                       shmdesc->addr +
996                                                       stuff->offset);
997
998        if (pMap) {
999            result = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid,
1000                              RT_PIXMAP, pMap, RT_NONE, NULL, DixCreateAccess);
1001            if (result != Success) {
1002                pDraw->pScreen->DestroyPixmap(pMap);
1003                break;
1004            }
1005            dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
1006            shmdesc->refcnt++;
1007            pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1008            pMap->drawable.id = newPix->info[j].id;
1009            if (!AddResource(newPix->info[j].id, RT_PIXMAP, (void *) pMap)) {
1010                result = BadAlloc;
1011                break;
1012            }
1013        }
1014        else {
1015            result = BadAlloc;
1016            break;
1017        }
1018    }
1019
1020    if (result != Success) {
1021        while (j--)
1022            FreeResource(newPix->info[j].id, RT_NONE);
1023        free(newPix);
1024    }
1025    else
1026        AddResource(stuff->pid, XRT_PIXMAP, newPix);
1027
1028    return result;
1029}
1030#endif
1031
1032static PixmapPtr
1033fbShmCreatePixmap(ScreenPtr pScreen,
1034                  int width, int height, int depth, char *addr)
1035{
1036    PixmapPtr pPixmap;
1037
1038    pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0);
1039    if (!pPixmap)
1040        return NullPixmap;
1041
1042    if (!(*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth,
1043                                         BitsPerPixel(depth),
1044                                         PixmapBytePad(width, depth),
1045                                         (void *) addr)) {
1046        (*pScreen->DestroyPixmap) (pPixmap);
1047        return NullPixmap;
1048    }
1049    return pPixmap;
1050}
1051
1052static int
1053ProcShmCreatePixmap(ClientPtr client)
1054{
1055    PixmapPtr pMap;
1056    DrawablePtr pDraw;
1057    DepthPtr pDepth;
1058    int i, rc;
1059    ShmDescPtr shmdesc;
1060    ShmScrPrivateRec *screen_priv;
1061
1062    REQUEST(xShmCreatePixmapReq);
1063    unsigned int width, height, depth;
1064    unsigned long size;
1065
1066    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1067    client->errorValue = stuff->pid;
1068    if (!sharedPixmaps)
1069        return BadImplementation;
1070    LEGAL_NEW_RESOURCE(stuff->pid, client);
1071    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
1072                           DixGetAttrAccess);
1073    if (rc != Success)
1074        return rc;
1075
1076    VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
1077
1078    width = stuff->width;
1079    height = stuff->height;
1080    depth = stuff->depth;
1081    if (!width || !height || !depth) {
1082        client->errorValue = 0;
1083        return BadValue;
1084    }
1085    if (width > 32767 || height > 32767)
1086        return BadAlloc;
1087
1088    if (stuff->depth != 1) {
1089        pDepth = pDraw->pScreen->allowedDepths;
1090        for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
1091            if (pDepth->depth == stuff->depth)
1092                goto CreatePmap;
1093        client->errorValue = stuff->depth;
1094        return BadValue;
1095    }
1096
1097 CreatePmap:
1098    size = PixmapBytePad(width, depth) * height;
1099    if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
1100        if (size < width * height)
1101            return BadAlloc;
1102    }
1103    /* thankfully, offset is unsigned */
1104    if (stuff->offset + size < size)
1105        return BadAlloc;
1106
1107    VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
1108    screen_priv = ShmGetScreenPriv(pDraw->pScreen);
1109    pMap = (*screen_priv->shmFuncs->CreatePixmap) (pDraw->pScreen, stuff->width,
1110                                                   stuff->height, stuff->depth,
1111                                                   shmdesc->addr +
1112                                                   stuff->offset);
1113    if (pMap) {
1114        rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP,
1115                      pMap, RT_NONE, NULL, DixCreateAccess);
1116        if (rc != Success) {
1117            pDraw->pScreen->DestroyPixmap(pMap);
1118            return rc;
1119        }
1120        dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
1121        shmdesc->refcnt++;
1122        pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1123        pMap->drawable.id = stuff->pid;
1124        if (AddResource(stuff->pid, RT_PIXMAP, (void *) pMap)) {
1125            return Success;
1126        }
1127    }
1128    return BadAlloc;
1129}
1130
1131#ifdef SHM_FD_PASSING
1132
1133static void
1134ShmBusfaultNotify(void *context)
1135{
1136    ShmDescPtr shmdesc = context;
1137
1138    ErrorF("shared memory 0x%x truncated by client\n",
1139           (unsigned int) shmdesc->resource);
1140    busfault_unregister(shmdesc->busfault);
1141    shmdesc->busfault = NULL;
1142    FreeResource (shmdesc->resource, RT_NONE);
1143}
1144
1145static int
1146ProcShmAttachFd(ClientPtr client)
1147{
1148    int fd;
1149    ShmDescPtr shmdesc;
1150    REQUEST(xShmAttachFdReq);
1151    struct stat statb;
1152
1153    SetReqFds(client, 1);
1154    REQUEST_SIZE_MATCH(xShmAttachFdReq);
1155    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
1156    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1157        client->errorValue = stuff->readOnly;
1158        return BadValue;
1159    }
1160    fd = ReadFdFromClient(client);
1161    if (fd < 0)
1162        return BadMatch;
1163
1164    if (fstat(fd, &statb) < 0 || statb.st_size == 0) {
1165        close(fd);
1166        return BadMatch;
1167    }
1168
1169    shmdesc = malloc(sizeof(ShmDescRec));
1170    if (!shmdesc) {
1171        close(fd);
1172        return BadAlloc;
1173    }
1174    shmdesc->is_fd = TRUE;
1175    shmdesc->addr = mmap(NULL, statb.st_size,
1176                         stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1177                         MAP_SHARED,
1178                         fd, 0);
1179
1180    close(fd);
1181    if (shmdesc->addr == ((char *) -1)) {
1182        free(shmdesc);
1183        return BadAccess;
1184    }
1185
1186    shmdesc->refcnt = 1;
1187    shmdesc->writable = !stuff->readOnly;
1188    shmdesc->size = statb.st_size;
1189    shmdesc->resource = stuff->shmseg;
1190
1191    shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1192    if (!shmdesc->busfault) {
1193        munmap(shmdesc->addr, shmdesc->size);
1194        free(shmdesc);
1195        return BadAlloc;
1196    }
1197
1198    shmdesc->next = Shmsegs;
1199    Shmsegs = shmdesc;
1200
1201    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
1202        return BadAlloc;
1203    return Success;
1204}
1205
1206static int
1207shm_tmpfile(void)
1208{
1209    const char *shmdirs[] = {
1210        "/run/shm",
1211        "/var/tmp",
1212        "/tmp",
1213    };
1214    int	fd;
1215
1216#ifdef HAVE_MEMFD_CREATE
1217    fd = memfd_create("xorg", MFD_CLOEXEC|MFD_ALLOW_SEALING);
1218    if (fd != -1) {
1219        fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
1220        DebugF ("Using memfd_create\n");
1221        return fd;
1222    }
1223#endif
1224
1225#ifdef O_TMPFILE
1226    for (int i = 0; i < ARRAY_SIZE(shmdirs); i++) {
1227        fd = open(shmdirs[i], O_TMPFILE|O_RDWR|O_CLOEXEC|O_EXCL, 0666);
1228        if (fd >= 0) {
1229            DebugF ("Using O_TMPFILE\n");
1230            return fd;
1231        }
1232    }
1233    ErrorF ("Not using O_TMPFILE\n");
1234#endif
1235
1236    for (int i = 0; i < ARRAY_SIZE(shmdirs); i++) {
1237        char template[PATH_MAX];
1238        snprintf(template, ARRAY_SIZE(template), "%s/shmfd-XXXXXX", shmdirs[i]);
1239#ifdef HAVE_MKOSTEMP
1240        fd = mkostemp(template, O_CLOEXEC);
1241#else
1242        fd = mkstemp(template);
1243#endif
1244        if (fd < 0)
1245            continue;
1246        unlink(template);
1247#ifndef HAVE_MKOSTEMP
1248        int flags = fcntl(fd, F_GETFD);
1249        if (flags != -1) {
1250            flags |= FD_CLOEXEC;
1251            (void) fcntl(fd, F_SETFD, &flags);
1252        }
1253#endif
1254        return fd;
1255    }
1256
1257    return -1;
1258}
1259
1260static int
1261ProcShmCreateSegment(ClientPtr client)
1262{
1263    int fd;
1264    ShmDescPtr shmdesc;
1265    REQUEST(xShmCreateSegmentReq);
1266    xShmCreateSegmentReply rep = {
1267        .type = X_Reply,
1268        .nfd = 1,
1269        .sequenceNumber = client->sequence,
1270        .length = 0,
1271    };
1272
1273    REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
1274    LEGAL_NEW_RESOURCE(stuff->shmseg, client);
1275    if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
1276        client->errorValue = stuff->readOnly;
1277        return BadValue;
1278    }
1279    fd = shm_tmpfile();
1280    if (fd < 0)
1281        return BadAlloc;
1282    if (ftruncate(fd, stuff->size) < 0) {
1283        close(fd);
1284        return BadAlloc;
1285    }
1286    shmdesc = malloc(sizeof(ShmDescRec));
1287    if (!shmdesc) {
1288        close(fd);
1289        return BadAlloc;
1290    }
1291    shmdesc->is_fd = TRUE;
1292    shmdesc->addr = mmap(NULL, stuff->size,
1293                         stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
1294                         MAP_SHARED,
1295                         fd, 0);
1296
1297    if (shmdesc->addr == ((char *) -1)) {
1298        close(fd);
1299        free(shmdesc);
1300        return BadAccess;
1301    }
1302
1303    shmdesc->refcnt = 1;
1304    shmdesc->writable = !stuff->readOnly;
1305    shmdesc->size = stuff->size;
1306
1307    shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
1308    if (!shmdesc->busfault) {
1309        close(fd);
1310        munmap(shmdesc->addr, shmdesc->size);
1311        free(shmdesc);
1312        return BadAlloc;
1313    }
1314
1315    shmdesc->next = Shmsegs;
1316    Shmsegs = shmdesc;
1317
1318    if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc)) {
1319        close(fd);
1320        return BadAlloc;
1321    }
1322
1323    if (WriteFdToClient(client, fd, TRUE) < 0) {
1324        FreeResource(stuff->shmseg, RT_NONE);
1325        close(fd);
1326        return BadAlloc;
1327    }
1328    WriteToClient(client, sizeof (xShmCreateSegmentReply), &rep);
1329    return Success;
1330}
1331#endif /* SHM_FD_PASSING */
1332
1333static int
1334ProcShmDispatch(ClientPtr client)
1335{
1336    REQUEST(xReq);
1337
1338    if (stuff->data == X_ShmQueryVersion)
1339        return ProcShmQueryVersion(client);
1340
1341    if (!client->local)
1342        return BadRequest;
1343
1344    switch (stuff->data) {
1345    case X_ShmAttach:
1346        return ProcShmAttach(client);
1347    case X_ShmDetach:
1348        return ProcShmDetach(client);
1349    case X_ShmPutImage:
1350#ifdef PANORAMIX
1351        if (!noPanoramiXExtension)
1352            return ProcPanoramiXShmPutImage(client);
1353#endif
1354        return ProcShmPutImage(client);
1355    case X_ShmGetImage:
1356#ifdef PANORAMIX
1357        if (!noPanoramiXExtension)
1358            return ProcPanoramiXShmGetImage(client);
1359#endif
1360        return ProcShmGetImage(client);
1361    case X_ShmCreatePixmap:
1362#ifdef PANORAMIX
1363        if (!noPanoramiXExtension)
1364            return ProcPanoramiXShmCreatePixmap(client);
1365#endif
1366        return ProcShmCreatePixmap(client);
1367#ifdef SHM_FD_PASSING
1368    case X_ShmAttachFd:
1369        return ProcShmAttachFd(client);
1370    case X_ShmCreateSegment:
1371        return ProcShmCreateSegment(client);
1372#endif
1373    default:
1374        return BadRequest;
1375    }
1376}
1377
1378static void _X_COLD
1379SShmCompletionEvent(xShmCompletionEvent * from, xShmCompletionEvent * to)
1380{
1381    to->type = from->type;
1382    cpswaps(from->sequenceNumber, to->sequenceNumber);
1383    cpswapl(from->drawable, to->drawable);
1384    cpswaps(from->minorEvent, to->minorEvent);
1385    to->majorEvent = from->majorEvent;
1386    cpswapl(from->shmseg, to->shmseg);
1387    cpswapl(from->offset, to->offset);
1388}
1389
1390static int _X_COLD
1391SProcShmQueryVersion(ClientPtr client)
1392{
1393    REQUEST(xShmQueryVersionReq);
1394
1395    swaps(&stuff->length);
1396    return ProcShmQueryVersion(client);
1397}
1398
1399static int _X_COLD
1400SProcShmAttach(ClientPtr client)
1401{
1402    REQUEST(xShmAttachReq);
1403    swaps(&stuff->length);
1404    REQUEST_SIZE_MATCH(xShmAttachReq);
1405    swapl(&stuff->shmseg);
1406    swapl(&stuff->shmid);
1407    return ProcShmAttach(client);
1408}
1409
1410static int _X_COLD
1411SProcShmDetach(ClientPtr client)
1412{
1413    REQUEST(xShmDetachReq);
1414    swaps(&stuff->length);
1415    REQUEST_SIZE_MATCH(xShmDetachReq);
1416    swapl(&stuff->shmseg);
1417    return ProcShmDetach(client);
1418}
1419
1420static int _X_COLD
1421SProcShmPutImage(ClientPtr client)
1422{
1423    REQUEST(xShmPutImageReq);
1424    swaps(&stuff->length);
1425    REQUEST_SIZE_MATCH(xShmPutImageReq);
1426    swapl(&stuff->drawable);
1427    swapl(&stuff->gc);
1428    swaps(&stuff->totalWidth);
1429    swaps(&stuff->totalHeight);
1430    swaps(&stuff->srcX);
1431    swaps(&stuff->srcY);
1432    swaps(&stuff->srcWidth);
1433    swaps(&stuff->srcHeight);
1434    swaps(&stuff->dstX);
1435    swaps(&stuff->dstY);
1436    swapl(&stuff->shmseg);
1437    swapl(&stuff->offset);
1438    return ProcShmPutImage(client);
1439}
1440
1441static int _X_COLD
1442SProcShmGetImage(ClientPtr client)
1443{
1444    REQUEST(xShmGetImageReq);
1445    swaps(&stuff->length);
1446    REQUEST_SIZE_MATCH(xShmGetImageReq);
1447    swapl(&stuff->drawable);
1448    swaps(&stuff->x);
1449    swaps(&stuff->y);
1450    swaps(&stuff->width);
1451    swaps(&stuff->height);
1452    swapl(&stuff->planeMask);
1453    swapl(&stuff->shmseg);
1454    swapl(&stuff->offset);
1455    return ProcShmGetImage(client);
1456}
1457
1458static int _X_COLD
1459SProcShmCreatePixmap(ClientPtr client)
1460{
1461    REQUEST(xShmCreatePixmapReq);
1462    swaps(&stuff->length);
1463    REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1464    swapl(&stuff->pid);
1465    swapl(&stuff->drawable);
1466    swaps(&stuff->width);
1467    swaps(&stuff->height);
1468    swapl(&stuff->shmseg);
1469    swapl(&stuff->offset);
1470    return ProcShmCreatePixmap(client);
1471}
1472
1473#ifdef SHM_FD_PASSING
1474static int _X_COLD
1475SProcShmAttachFd(ClientPtr client)
1476{
1477    REQUEST(xShmAttachFdReq);
1478    SetReqFds(client, 1);
1479    swaps(&stuff->length);
1480    REQUEST_SIZE_MATCH(xShmAttachFdReq);
1481    swapl(&stuff->shmseg);
1482    return ProcShmAttachFd(client);
1483}
1484
1485static int _X_COLD
1486SProcShmCreateSegment(ClientPtr client)
1487{
1488    REQUEST(xShmCreateSegmentReq);
1489    swaps(&stuff->length);
1490    REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
1491    swapl(&stuff->shmseg);
1492    swapl(&stuff->size);
1493    return ProcShmCreateSegment(client);
1494}
1495#endif  /* SHM_FD_PASSING */
1496
1497static int _X_COLD
1498SProcShmDispatch(ClientPtr client)
1499{
1500    REQUEST(xReq);
1501
1502    if (stuff->data == X_ShmQueryVersion)
1503        return SProcShmQueryVersion(client);
1504
1505    if (!client->local)
1506        return BadRequest;
1507
1508    switch (stuff->data) {
1509    case X_ShmAttach:
1510        return SProcShmAttach(client);
1511    case X_ShmDetach:
1512        return SProcShmDetach(client);
1513    case X_ShmPutImage:
1514        return SProcShmPutImage(client);
1515    case X_ShmGetImage:
1516        return SProcShmGetImage(client);
1517    case X_ShmCreatePixmap:
1518        return SProcShmCreatePixmap(client);
1519#ifdef SHM_FD_PASSING
1520    case X_ShmAttachFd:
1521        return SProcShmAttachFd(client);
1522    case X_ShmCreateSegment:
1523        return SProcShmCreateSegment(client);
1524#endif
1525    default:
1526        return BadRequest;
1527    }
1528}
1529
1530void
1531ShmExtensionInit(void)
1532{
1533    ExtensionEntry *extEntry;
1534    int i;
1535
1536#ifdef MUST_CHECK_FOR_SHM_SYSCALL
1537    if (!CheckForShmSyscall()) {
1538        ErrorF("MIT-SHM extension disabled due to lack of kernel support\n");
1539        return;
1540    }
1541#endif
1542
1543    if (!ShmRegisterPrivates())
1544        return;
1545
1546    sharedPixmaps = xFalse;
1547    {
1548        sharedPixmaps = xTrue;
1549        for (i = 0; i < screenInfo.numScreens; i++) {
1550            ShmScrPrivateRec *screen_priv =
1551                ShmInitScreenPriv(screenInfo.screens[i]);
1552            if (!screen_priv->shmFuncs)
1553                screen_priv->shmFuncs = &miFuncs;
1554            if (!screen_priv->shmFuncs->CreatePixmap)
1555                sharedPixmaps = xFalse;
1556        }
1557        if (sharedPixmaps)
1558            for (i = 0; i < screenInfo.numScreens; i++) {
1559                ShmScrPrivateRec *screen_priv =
1560                    ShmGetScreenPriv(screenInfo.screens[i]);
1561                screen_priv->destroyPixmap =
1562                    screenInfo.screens[i]->DestroyPixmap;
1563                screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap;
1564            }
1565    }
1566    ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg");
1567    if (ShmSegType &&
1568        (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors,
1569                                 ProcShmDispatch, SProcShmDispatch,
1570                                 ShmResetProc, StandardMinorOpcode))) {
1571        ShmReqCode = (unsigned char) extEntry->base;
1572        ShmCompletionCode = extEntry->eventBase;
1573        BadShmSegCode = extEntry->errorBase;
1574        SetResourceTypeErrorValue(ShmSegType, BadShmSegCode);
1575        EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent;
1576    }
1577}
1578