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