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