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