shm.c revision 05b261ec
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 30#define SHM 31 32#ifdef HAVE_DIX_CONFIG_H 33#include <dix-config.h> 34#endif 35 36#include <sys/types.h> 37#ifndef Lynx 38#include <sys/ipc.h> 39#include <sys/shm.h> 40#else 41#include <ipc.h> 42#include <shm.h> 43#endif 44#include <unistd.h> 45#include <sys/stat.h> 46#define NEED_REPLIES 47#define NEED_EVENTS 48#include <X11/X.h> 49#include <X11/Xproto.h> 50#include "misc.h" 51#include "os.h" 52#include "dixstruct.h" 53#include "resource.h" 54#include "scrnintstr.h" 55#include "windowstr.h" 56#include "pixmapstr.h" 57#include "gcstruct.h" 58#include "extnsionst.h" 59#include "servermd.h" 60#define _XSHM_SERVER_ 61#include <X11/extensions/shmstr.h> 62#include <X11/Xfuncproto.h> 63 64#ifdef PANORAMIX 65#include "panoramiX.h" 66#include "panoramiXsrv.h" 67#endif 68 69#include "modinit.h" 70 71typedef struct _ShmDesc { 72 struct _ShmDesc *next; 73 int shmid; 74 int refcnt; 75 char *addr; 76 Bool writable; 77 unsigned long size; 78} ShmDescRec, *ShmDescPtr; 79 80static void miShmPutImage(XSHM_PUT_IMAGE_ARGS); 81static void fbShmPutImage(XSHM_PUT_IMAGE_ARGS); 82static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS); 83static int ShmDetachSegment( 84 pointer /* value */, 85 XID /* shmseg */ 86 ); 87static void ShmResetProc( 88 ExtensionEntry * /* extEntry */ 89 ); 90static void SShmCompletionEvent( 91 xShmCompletionEvent * /* from */, 92 xShmCompletionEvent * /* to */ 93 ); 94 95static Bool ShmDestroyPixmap (PixmapPtr pPixmap); 96 97static DISPATCH_PROC(ProcShmAttach); 98static DISPATCH_PROC(ProcShmCreatePixmap); 99static DISPATCH_PROC(ProcShmDetach); 100static DISPATCH_PROC(ProcShmDispatch); 101static DISPATCH_PROC(ProcShmGetImage); 102static DISPATCH_PROC(ProcShmPutImage); 103static DISPATCH_PROC(ProcShmQueryVersion); 104static DISPATCH_PROC(SProcShmAttach); 105static DISPATCH_PROC(SProcShmCreatePixmap); 106static DISPATCH_PROC(SProcShmDetach); 107static DISPATCH_PROC(SProcShmDispatch); 108static DISPATCH_PROC(SProcShmGetImage); 109static DISPATCH_PROC(SProcShmPutImage); 110static DISPATCH_PROC(SProcShmQueryVersion); 111 112static unsigned char ShmReqCode; 113_X_EXPORT int ShmCompletionCode; 114_X_EXPORT int BadShmSegCode; 115_X_EXPORT RESTYPE ShmSegType; 116static ShmDescPtr Shmsegs; 117static Bool sharedPixmaps; 118static int pixmapFormat; 119static int shmPixFormat[MAXSCREENS]; 120static ShmFuncsPtr shmFuncs[MAXSCREENS]; 121static DestroyPixmapProcPtr destroyPixmap[MAXSCREENS]; 122static int shmPixmapPrivate; 123static ShmFuncs miFuncs = {NULL, miShmPutImage}; 124static ShmFuncs fbFuncs = {fbShmCreatePixmap, fbShmPutImage}; 125 126#define VERIFY_SHMSEG(shmseg,shmdesc,client) \ 127{ \ 128 shmdesc = (ShmDescPtr)LookupIDByType(shmseg, ShmSegType); \ 129 if (!shmdesc) \ 130 { \ 131 client->errorValue = shmseg; \ 132 return BadShmSegCode; \ 133 } \ 134} 135 136#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \ 137{ \ 138 VERIFY_SHMSEG(shmseg, shmdesc, client); \ 139 if ((offset & 3) || (offset > shmdesc->size)) \ 140 { \ 141 client->errorValue = offset; \ 142 return BadValue; \ 143 } \ 144 if (needwrite && !shmdesc->writable) \ 145 return BadAccess; \ 146} 147 148#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \ 149{ \ 150 if ((offset + len) > shmdesc->size) \ 151 { \ 152 return BadAccess; \ 153 } \ 154} 155 156 157#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__) 158#include <sys/signal.h> 159 160static Bool badSysCall = FALSE; 161 162static void 163SigSysHandler(signo) 164int signo; 165{ 166 badSysCall = TRUE; 167} 168 169static Bool CheckForShmSyscall() 170{ 171 void (*oldHandler)(); 172 int shmid = -1; 173 174 /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */ 175 oldHandler = signal(SIGSYS, SigSysHandler); 176 177 badSysCall = FALSE; 178 shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT); 179 180 if (shmid != -1) 181 { 182 /* Successful allocation - clean up */ 183 shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL); 184 } 185 else 186 { 187 /* Allocation failed */ 188 badSysCall = TRUE; 189 } 190 signal(SIGSYS, oldHandler); 191 return(!badSysCall); 192} 193 194#define MUST_CHECK_FOR_SHM_SYSCALL 195 196#endif 197 198void 199ShmExtensionInit(INITARGS) 200{ 201 ExtensionEntry *extEntry; 202 int i; 203 204#ifdef MUST_CHECK_FOR_SHM_SYSCALL 205 if (!CheckForShmSyscall()) 206 { 207 ErrorF("MIT-SHM extension disabled due to lack of kernel support\n"); 208 return; 209 } 210#endif 211 212 sharedPixmaps = xFalse; 213 pixmapFormat = 0; 214 { 215 sharedPixmaps = xTrue; 216 pixmapFormat = shmPixFormat[0]; 217 for (i = 0; i < screenInfo.numScreens; i++) 218 { 219 if (!shmFuncs[i]) 220 shmFuncs[i] = &miFuncs; 221 if (!shmFuncs[i]->CreatePixmap) 222 sharedPixmaps = xFalse; 223 if (shmPixFormat[i] && (shmPixFormat[i] != pixmapFormat)) 224 { 225 sharedPixmaps = xFalse; 226 pixmapFormat = 0; 227 } 228 } 229 if (!pixmapFormat) 230 pixmapFormat = ZPixmap; 231 if (sharedPixmaps) 232 { 233 for (i = 0; i < screenInfo.numScreens; i++) 234 { 235 destroyPixmap[i] = screenInfo.screens[i]->DestroyPixmap; 236 screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap; 237 } 238 shmPixmapPrivate = AllocatePixmapPrivateIndex(); 239 for (i = 0; i < screenInfo.numScreens; i++) 240 { 241 if (!AllocatePixmapPrivate(screenInfo.screens[i], 242 shmPixmapPrivate, 0)) 243 return; 244 } 245 } 246 } 247 ShmSegType = CreateNewResourceType(ShmDetachSegment); 248 if (ShmSegType && 249 (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors, 250 ProcShmDispatch, SProcShmDispatch, 251 ShmResetProc, StandardMinorOpcode))) 252 { 253 ShmReqCode = (unsigned char)extEntry->base; 254 ShmCompletionCode = extEntry->eventBase; 255 BadShmSegCode = extEntry->errorBase; 256 EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent; 257 } 258} 259 260/*ARGSUSED*/ 261static void 262ShmResetProc (extEntry) 263ExtensionEntry *extEntry; 264{ 265 int i; 266 267 for (i = 0; i < MAXSCREENS; i++) 268 { 269 shmFuncs[i] = (ShmFuncsPtr)NULL; 270 shmPixFormat[i] = 0; 271 } 272} 273 274void 275ShmRegisterFuncs( 276 ScreenPtr pScreen, 277 ShmFuncsPtr funcs) 278{ 279 shmFuncs[pScreen->myNum] = funcs; 280} 281 282void 283ShmSetPixmapFormat( 284 ScreenPtr pScreen, 285 int format) 286{ 287 shmPixFormat[pScreen->myNum] = format; 288} 289 290static Bool 291ShmDestroyPixmap (PixmapPtr pPixmap) 292{ 293 ScreenPtr pScreen = pPixmap->drawable.pScreen; 294 Bool ret; 295 if (pPixmap->refcnt == 1) 296 { 297 ShmDescPtr shmdesc; 298 shmdesc = (ShmDescPtr) pPixmap->devPrivates[shmPixmapPrivate].ptr; 299 if (shmdesc) 300 ShmDetachSegment ((pointer) shmdesc, pPixmap->drawable.id); 301 } 302 303 pScreen->DestroyPixmap = destroyPixmap[pScreen->myNum]; 304 ret = (*pScreen->DestroyPixmap) (pPixmap); 305 destroyPixmap[pScreen->myNum] = pScreen->DestroyPixmap; 306 pScreen->DestroyPixmap = ShmDestroyPixmap; 307 return ret; 308} 309 310void 311ShmRegisterFbFuncs(pScreen) 312 ScreenPtr pScreen; 313{ 314 shmFuncs[pScreen->myNum] = &fbFuncs; 315} 316 317static int 318ProcShmQueryVersion(client) 319 register ClientPtr client; 320{ 321 xShmQueryVersionReply rep; 322 register int n; 323 324 REQUEST_SIZE_MATCH(xShmQueryVersionReq); 325 rep.type = X_Reply; 326 rep.length = 0; 327 rep.sequenceNumber = client->sequence; 328 rep.sharedPixmaps = sharedPixmaps; 329 rep.pixmapFormat = pixmapFormat; 330 rep.majorVersion = SHM_MAJOR_VERSION; 331 rep.minorVersion = SHM_MINOR_VERSION; 332 rep.uid = geteuid(); 333 rep.gid = getegid(); 334 if (client->swapped) { 335 swaps(&rep.sequenceNumber, n); 336 swapl(&rep.length, n); 337 swaps(&rep.majorVersion, n); 338 swaps(&rep.minorVersion, n); 339 swaps(&rep.uid, n); 340 swaps(&rep.gid, n); 341 } 342 WriteToClient(client, sizeof(xShmQueryVersionReply), (char *)&rep); 343 return (client->noClientException); 344} 345 346/* 347 * Simulate the access() system call for a shared memory segement, 348 * using the credentials from the client if available 349 */ 350static int 351shm_access(ClientPtr client, struct ipc_perm *perm, int readonly) 352{ 353 int uid, gid; 354 mode_t mask; 355 356 if (LocalClientCred(client, &uid, &gid) != -1) { 357 358 /* User id 0 always gets access */ 359 if (uid == 0) { 360 return 0; 361 } 362 /* Check the owner */ 363 if (perm->uid == uid || perm->cuid == uid) { 364 mask = S_IRUSR; 365 if (!readonly) { 366 mask |= S_IWUSR; 367 } 368 return (perm->mode & mask) == mask ? 0 : -1; 369 } 370 /* Check the group */ 371 if (perm->gid == gid || perm->cgid == gid) { 372 mask = S_IRGRP; 373 if (!readonly) { 374 mask |= S_IWGRP; 375 } 376 return (perm->mode & mask) == mask ? 0 : -1; 377 } 378 } 379 /* Otherwise, check everyone else */ 380 mask = S_IROTH; 381 if (!readonly) { 382 mask |= S_IWOTH; 383 } 384 return (perm->mode & mask) == mask ? 0 : -1; 385} 386 387static int 388ProcShmAttach(client) 389 register ClientPtr client; 390{ 391 struct shmid_ds buf; 392 ShmDescPtr shmdesc; 393 REQUEST(xShmAttachReq); 394 395 REQUEST_SIZE_MATCH(xShmAttachReq); 396 LEGAL_NEW_RESOURCE(stuff->shmseg, client); 397 if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) 398 { 399 client->errorValue = stuff->readOnly; 400 return(BadValue); 401 } 402 for (shmdesc = Shmsegs; 403 shmdesc && (shmdesc->shmid != stuff->shmid); 404 shmdesc = shmdesc->next) 405 ; 406 if (shmdesc) 407 { 408 if (!stuff->readOnly && !shmdesc->writable) 409 return BadAccess; 410 shmdesc->refcnt++; 411 } 412 else 413 { 414 shmdesc = (ShmDescPtr) xalloc(sizeof(ShmDescRec)); 415 if (!shmdesc) 416 return BadAlloc; 417 shmdesc->addr = shmat(stuff->shmid, 0, 418 stuff->readOnly ? SHM_RDONLY : 0); 419 if ((shmdesc->addr == ((char *)-1)) || 420 shmctl(stuff->shmid, IPC_STAT, &buf)) 421 { 422 xfree(shmdesc); 423 return BadAccess; 424 } 425 426 /* The attach was performed with root privs. We must 427 * do manual checking of access rights for the credentials 428 * of the client */ 429 430 if (shm_access(client, &(buf.shm_perm), stuff->readOnly) == -1) { 431 shmdt(shmdesc->addr); 432 xfree(shmdesc); 433 return BadAccess; 434 } 435 436 shmdesc->shmid = stuff->shmid; 437 shmdesc->refcnt = 1; 438 shmdesc->writable = !stuff->readOnly; 439 shmdesc->size = buf.shm_segsz; 440 shmdesc->next = Shmsegs; 441 Shmsegs = shmdesc; 442 } 443 if (!AddResource(stuff->shmseg, ShmSegType, (pointer)shmdesc)) 444 return BadAlloc; 445 return(client->noClientException); 446} 447 448/*ARGSUSED*/ 449static int 450ShmDetachSegment(value, shmseg) 451 pointer value; /* must conform to DeleteType */ 452 XID shmseg; 453{ 454 ShmDescPtr shmdesc = (ShmDescPtr)value; 455 ShmDescPtr *prev; 456 457 if (--shmdesc->refcnt) 458 return TRUE; 459 shmdt(shmdesc->addr); 460 for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next) 461 ; 462 *prev = shmdesc->next; 463 xfree(shmdesc); 464 return Success; 465} 466 467static int 468ProcShmDetach(client) 469 register ClientPtr client; 470{ 471 ShmDescPtr shmdesc; 472 REQUEST(xShmDetachReq); 473 474 REQUEST_SIZE_MATCH(xShmDetachReq); 475 VERIFY_SHMSEG(stuff->shmseg, shmdesc, client); 476 FreeResource(stuff->shmseg, RT_NONE); 477 return(client->noClientException); 478} 479 480static void 481miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data) 482 DrawablePtr dst; 483 GCPtr pGC; 484 int depth, w, h, sx, sy, sw, sh, dx, dy; 485 unsigned int format; 486 char *data; 487{ 488 PixmapPtr pmap; 489 GCPtr putGC; 490 491 putGC = GetScratchGC(depth, dst->pScreen); 492 if (!putGC) 493 return; 494 pmap = (*dst->pScreen->CreatePixmap)(dst->pScreen, sw, sh, depth); 495 if (!pmap) 496 { 497 FreeScratchGC(putGC); 498 return; 499 } 500 ValidateGC((DrawablePtr)pmap, putGC); 501 (*putGC->ops->PutImage)((DrawablePtr)pmap, putGC, depth, -sx, -sy, w, h, 0, 502 (format == XYPixmap) ? XYPixmap : ZPixmap, data); 503 FreeScratchGC(putGC); 504 if (format == XYBitmap) 505 (void)(*pGC->ops->CopyPlane)((DrawablePtr)pmap, dst, pGC, 0, 0, sw, sh, 506 dx, dy, 1L); 507 else 508 (void)(*pGC->ops->CopyArea)((DrawablePtr)pmap, dst, pGC, 0, 0, sw, sh, 509 dx, dy); 510 (*pmap->drawable.pScreen->DestroyPixmap)(pmap); 511} 512 513static void 514fbShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data) 515 DrawablePtr dst; 516 GCPtr pGC; 517 int depth, w, h, sx, sy, sw, sh, dx, dy; 518 unsigned int format; 519 char *data; 520{ 521 if ((format == ZPixmap) || (depth == 1)) 522 { 523 PixmapPtr pPixmap; 524 525 pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth, 526 BitsPerPixel(depth), PixmapBytePad(w, depth), (pointer)data); 527 if (!pPixmap) 528 return; 529 if (format == XYBitmap) 530 (void)(*pGC->ops->CopyPlane)((DrawablePtr)pPixmap, dst, pGC, 531 sx, sy, sw, sh, dx, dy, 1L); 532 else 533 (void)(*pGC->ops->CopyArea)((DrawablePtr)pPixmap, dst, pGC, 534 sx, sy, sw, sh, dx, dy); 535 FreeScratchPixmapHeader(pPixmap); 536 } 537 else 538 miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, 539 data); 540} 541 542 543#ifdef PANORAMIX 544static int 545ProcPanoramiXShmPutImage(register ClientPtr client) 546{ 547 int j, result = 0, orig_x, orig_y; 548 PanoramiXRes *draw, *gc; 549 Bool sendEvent, isRoot; 550 551 REQUEST(xShmPutImageReq); 552 REQUEST_SIZE_MATCH(xShmPutImageReq); 553 554 if(!(draw = (PanoramiXRes *)SecurityLookupIDByClass( 555 client, stuff->drawable, XRC_DRAWABLE, DixWriteAccess))) 556 return BadDrawable; 557 558 if(!(gc = (PanoramiXRes *)SecurityLookupIDByType( 559 client, stuff->gc, XRT_GC, DixReadAccess))) 560 return BadGC; 561 562 isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; 563 564 orig_x = stuff->dstX; 565 orig_y = stuff->dstY; 566 sendEvent = stuff->sendEvent; 567 stuff->sendEvent = 0; 568 FOR_NSCREENS(j) { 569 if(!j) stuff->sendEvent = sendEvent; 570 stuff->drawable = draw->info[j].id; 571 stuff->gc = gc->info[j].id; 572 if (isRoot) { 573 stuff->dstX = orig_x - panoramiXdataPtr[j].x; 574 stuff->dstY = orig_y - panoramiXdataPtr[j].y; 575 } 576 result = ProcShmPutImage(client); 577 if(result != client->noClientException) break; 578 } 579 return(result); 580} 581 582static int 583ProcPanoramiXShmGetImage(ClientPtr client) 584{ 585 PanoramiXRes *draw; 586 DrawablePtr drawables[MAXSCREENS]; 587 DrawablePtr pDraw; 588 xShmGetImageReply xgi; 589 ShmDescPtr shmdesc; 590 int i, x, y, w, h, format, rc; 591 Mask plane = 0, planemask; 592 long lenPer = 0, length, widthBytesLine; 593 Bool isRoot; 594 595 REQUEST(xShmGetImageReq); 596 597 REQUEST_SIZE_MATCH(xShmGetImageReq); 598 599 if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) { 600 client->errorValue = stuff->format; 601 return(BadValue); 602 } 603 604 if(!(draw = (PanoramiXRes *)SecurityLookupIDByClass( 605 client, stuff->drawable, XRC_DRAWABLE, DixWriteAccess))) 606 return BadDrawable; 607 608 if (draw->type == XRT_PIXMAP) 609 return ProcShmGetImage(client); 610 611 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, 612 DixUnknownAccess); 613 if (rc != Success) 614 return rc; 615 616 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 617 618 x = stuff->x; 619 y = stuff->y; 620 w = stuff->width; 621 h = stuff->height; 622 format = stuff->format; 623 planemask = stuff->planeMask; 624 625 isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; 626 627 if(isRoot) { 628 if( /* check for being onscreen */ 629 x < 0 || x + w > PanoramiXPixWidth || 630 y < 0 || y + h > PanoramiXPixHeight ) 631 return(BadMatch); 632 } else { 633 if( /* check for being onscreen */ 634 panoramiXdataPtr[0].x + pDraw->x + x < 0 || 635 panoramiXdataPtr[0].x + pDraw->x + x + w > PanoramiXPixWidth || 636 panoramiXdataPtr[0].y + pDraw->y + y < 0 || 637 panoramiXdataPtr[0].y + pDraw->y + y + h > PanoramiXPixHeight || 638 /* check for being inside of border */ 639 x < - wBorderWidth((WindowPtr)pDraw) || 640 x + w > wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || 641 y < -wBorderWidth((WindowPtr)pDraw) || 642 y + h > wBorderWidth ((WindowPtr)pDraw) + (int)pDraw->height) 643 return(BadMatch); 644 } 645 646 drawables[0] = pDraw; 647 for(i = 1; i < PanoramiXNumScreens; i++) { 648 rc = dixLookupDrawable(drawables+i, draw->info[i].id, client, 0, 649 DixUnknownAccess); 650 if (rc != Success) 651 return rc; 652 } 653 654 xgi.visual = wVisual(((WindowPtr)pDraw)); 655 xgi.type = X_Reply; 656 xgi.length = 0; 657 xgi.sequenceNumber = client->sequence; 658 xgi.depth = pDraw->depth; 659 660 if(format == ZPixmap) { 661 widthBytesLine = PixmapBytePad(w, pDraw->depth); 662 length = widthBytesLine * h; 663 } else { 664 widthBytesLine = PixmapBytePad(w, 1); 665 lenPer = widthBytesLine * h; 666 plane = ((Mask)1) << (pDraw->depth - 1); 667 length = lenPer * Ones(planemask & (plane | (plane - 1))); 668 } 669 670 VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); 671 xgi.size = length; 672 673 if (length == 0) {/* nothing to do */ } 674 else if (format == ZPixmap) { 675 XineramaGetImageData(drawables, x, y, w, h, format, planemask, 676 shmdesc->addr + stuff->offset, 677 widthBytesLine, isRoot); 678 } else { 679 680 length = stuff->offset; 681 for (; plane; plane >>= 1) { 682 if (planemask & plane) { 683 XineramaGetImageData(drawables, x, y, w, h, 684 format, plane, shmdesc->addr + length, 685 widthBytesLine, isRoot); 686 length += lenPer; 687 } 688 } 689 } 690 691 if (client->swapped) { 692 register int n; 693 swaps(&xgi.sequenceNumber, n); 694 swapl(&xgi.length, n); 695 swapl(&xgi.visual, n); 696 swapl(&xgi.size, n); 697 } 698 WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); 699 700 return(client->noClientException); 701} 702 703static int 704ProcPanoramiXShmCreatePixmap( 705 register ClientPtr client) 706{ 707 ScreenPtr pScreen = NULL; 708 PixmapPtr pMap = NULL; 709 DrawablePtr pDraw; 710 DepthPtr pDepth; 711 int i, j, result, rc; 712 ShmDescPtr shmdesc; 713 REQUEST(xShmCreatePixmapReq); 714 unsigned int width, height, depth; 715 unsigned long size; 716 PanoramiXRes *newPix; 717 718 REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 719 client->errorValue = stuff->pid; 720 if (!sharedPixmaps) 721 return BadImplementation; 722 LEGAL_NEW_RESOURCE(stuff->pid, client); 723 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, 724 DixUnknownAccess); 725 if (rc != Success) 726 return rc; 727 728 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 729 730 width = stuff->width; 731 height = stuff->height; 732 depth = stuff->depth; 733 if (!width || !height || !depth) 734 { 735 client->errorValue = 0; 736 return BadValue; 737 } 738 if (width > 32767 || height > 32767) 739 return BadAlloc; 740 741 if (stuff->depth != 1) 742 { 743 pDepth = pDraw->pScreen->allowedDepths; 744 for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++) 745 if (pDepth->depth == stuff->depth) 746 goto CreatePmap; 747 client->errorValue = stuff->depth; 748 return BadValue; 749 } 750 751CreatePmap: 752 size = PixmapBytePad(width, depth) * height; 753 if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { 754 if (size < width * height) 755 return BadAlloc; 756 } 757 /* thankfully, offset is unsigned */ 758 if (stuff->offset + size < size) 759 return BadAlloc; 760 761 VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); 762 763 if(!(newPix = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes)))) 764 return BadAlloc; 765 766 newPix->type = XRT_PIXMAP; 767 newPix->u.pix.shared = TRUE; 768 newPix->info[0].id = stuff->pid; 769 for(j = 1; j < PanoramiXNumScreens; j++) 770 newPix->info[j].id = FakeClientID(client->index); 771 772 result = (client->noClientException); 773 774 FOR_NSCREENS(j) { 775 pScreen = screenInfo.screens[j]; 776 777 pMap = (*shmFuncs[j]->CreatePixmap)(pScreen, 778 stuff->width, stuff->height, stuff->depth, 779 shmdesc->addr + stuff->offset); 780 781 if (pMap) { 782 pMap->devPrivates[shmPixmapPrivate].ptr = (pointer) shmdesc; 783 shmdesc->refcnt++; 784 pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 785 pMap->drawable.id = newPix->info[j].id; 786 if (!AddResource(newPix->info[j].id, RT_PIXMAP, (pointer)pMap)) { 787 (*pScreen->DestroyPixmap)(pMap); 788 result = BadAlloc; 789 break; 790 } 791 } else { 792 result = BadAlloc; 793 break; 794 } 795 } 796 797 if(result == BadAlloc) { 798 while(j--) { 799 (*pScreen->DestroyPixmap)(pMap); 800 FreeResource(newPix->info[j].id, RT_NONE); 801 } 802 xfree(newPix); 803 } else 804 AddResource(stuff->pid, XRT_PIXMAP, newPix); 805 806 return result; 807} 808 809#endif 810 811static int 812ProcShmPutImage(client) 813 register ClientPtr client; 814{ 815 GCPtr pGC; 816 DrawablePtr pDraw; 817 long length; 818 ShmDescPtr shmdesc; 819 REQUEST(xShmPutImageReq); 820 821 REQUEST_SIZE_MATCH(xShmPutImageReq); 822 VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); 823 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client); 824 if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse)) 825 return BadValue; 826 if (stuff->format == XYBitmap) 827 { 828 if (stuff->depth != 1) 829 return BadMatch; 830 length = PixmapBytePad(stuff->totalWidth, 1); 831 } 832 else if (stuff->format == XYPixmap) 833 { 834 if (pDraw->depth != stuff->depth) 835 return BadMatch; 836 length = PixmapBytePad(stuff->totalWidth, 1); 837 length *= stuff->depth; 838 } 839 else if (stuff->format == ZPixmap) 840 { 841 if (pDraw->depth != stuff->depth) 842 return BadMatch; 843 length = PixmapBytePad(stuff->totalWidth, stuff->depth); 844 } 845 else 846 { 847 client->errorValue = stuff->format; 848 return BadValue; 849 } 850 851 /* 852 * There's a potential integer overflow in this check: 853 * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight, 854 * client); 855 * the version below ought to avoid it 856 */ 857 if (stuff->totalHeight != 0 && 858 length > (shmdesc->size - stuff->offset)/stuff->totalHeight) { 859 client->errorValue = stuff->totalWidth; 860 return BadValue; 861 } 862 if (stuff->srcX > stuff->totalWidth) 863 { 864 client->errorValue = stuff->srcX; 865 return BadValue; 866 } 867 if (stuff->srcY > stuff->totalHeight) 868 { 869 client->errorValue = stuff->srcY; 870 return BadValue; 871 } 872 if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) 873 { 874 client->errorValue = stuff->srcWidth; 875 return BadValue; 876 } 877 if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) 878 { 879 client->errorValue = stuff->srcHeight; 880 return BadValue; 881 } 882 883 if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) || 884 ((stuff->format != ZPixmap) && 885 (stuff->srcX < screenInfo.bitmapScanlinePad) && 886 ((stuff->format == XYBitmap) || 887 ((stuff->srcY == 0) && 888 (stuff->srcHeight == stuff->totalHeight))))) && 889 ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth)) 890 (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, 891 stuff->dstX, stuff->dstY, 892 stuff->totalWidth, stuff->srcHeight, 893 stuff->srcX, stuff->format, 894 shmdesc->addr + stuff->offset + 895 (stuff->srcY * length)); 896 else 897 (*shmFuncs[pDraw->pScreen->myNum]->PutImage)( 898 pDraw, pGC, stuff->depth, stuff->format, 899 stuff->totalWidth, stuff->totalHeight, 900 stuff->srcX, stuff->srcY, 901 stuff->srcWidth, stuff->srcHeight, 902 stuff->dstX, stuff->dstY, 903 shmdesc->addr + stuff->offset); 904 905 if (stuff->sendEvent) 906 { 907 xShmCompletionEvent ev; 908 909 ev.type = ShmCompletionCode; 910 ev.drawable = stuff->drawable; 911 ev.sequenceNumber = client->sequence; 912 ev.minorEvent = X_ShmPutImage; 913 ev.majorEvent = ShmReqCode; 914 ev.shmseg = stuff->shmseg; 915 ev.offset = stuff->offset; 916 WriteEventsToClient(client, 1, (xEvent *) &ev); 917 } 918 919 return (client->noClientException); 920} 921 922 923 924static int 925ProcShmGetImage(client) 926 register ClientPtr client; 927{ 928 DrawablePtr pDraw; 929 long lenPer = 0, length; 930 Mask plane = 0; 931 xShmGetImageReply xgi; 932 ShmDescPtr shmdesc; 933 int n, rc; 934 935 REQUEST(xShmGetImageReq); 936 937 REQUEST_SIZE_MATCH(xShmGetImageReq); 938 if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) 939 { 940 client->errorValue = stuff->format; 941 return(BadValue); 942 } 943 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, 944 DixUnknownAccess); 945 if (rc != Success) 946 return rc; 947 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 948 if (pDraw->type == DRAWABLE_WINDOW) 949 { 950 if( /* check for being viewable */ 951 !((WindowPtr) pDraw)->realized || 952 /* check for being on screen */ 953 pDraw->x + stuff->x < 0 || 954 pDraw->x + stuff->x + (int)stuff->width > pDraw->pScreen->width || 955 pDraw->y + stuff->y < 0 || 956 pDraw->y + stuff->y + (int)stuff->height > pDraw->pScreen->height || 957 /* check for being inside of border */ 958 stuff->x < - wBorderWidth((WindowPtr)pDraw) || 959 stuff->x + (int)stuff->width > 960 wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || 961 stuff->y < -wBorderWidth((WindowPtr)pDraw) || 962 stuff->y + (int)stuff->height > 963 wBorderWidth((WindowPtr)pDraw) + (int)pDraw->height 964 ) 965 return(BadMatch); 966 xgi.visual = wVisual(((WindowPtr)pDraw)); 967 } 968 else 969 { 970 if (stuff->x < 0 || 971 stuff->x+(int)stuff->width > pDraw->width || 972 stuff->y < 0 || 973 stuff->y+(int)stuff->height > pDraw->height 974 ) 975 return(BadMatch); 976 xgi.visual = None; 977 } 978 xgi.type = X_Reply; 979 xgi.length = 0; 980 xgi.sequenceNumber = client->sequence; 981 xgi.depth = pDraw->depth; 982 if(stuff->format == ZPixmap) 983 { 984 length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height; 985 } 986 else 987 { 988 lenPer = PixmapBytePad(stuff->width, 1) * stuff->height; 989 plane = ((Mask)1) << (pDraw->depth - 1); 990 /* only planes asked for */ 991 length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1))); 992 } 993 994 VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); 995 xgi.size = length; 996 997 if (length == 0) 998 { 999 /* nothing to do */ 1000 } 1001 else if (stuff->format == ZPixmap) 1002 { 1003 (*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y, 1004 stuff->width, stuff->height, 1005 stuff->format, stuff->planeMask, 1006 shmdesc->addr + stuff->offset); 1007 } 1008 else 1009 { 1010 1011 length = stuff->offset; 1012 for (; plane; plane >>= 1) 1013 { 1014 if (stuff->planeMask & plane) 1015 { 1016 (*pDraw->pScreen->GetImage)(pDraw, 1017 stuff->x, stuff->y, 1018 stuff->width, stuff->height, 1019 stuff->format, plane, 1020 shmdesc->addr + length); 1021 length += lenPer; 1022 } 1023 } 1024 } 1025 1026 if (client->swapped) { 1027 swaps(&xgi.sequenceNumber, n); 1028 swapl(&xgi.length, n); 1029 swapl(&xgi.visual, n); 1030 swapl(&xgi.size, n); 1031 } 1032 WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); 1033 1034 return(client->noClientException); 1035} 1036 1037static PixmapPtr 1038fbShmCreatePixmap (pScreen, width, height, depth, addr) 1039 ScreenPtr pScreen; 1040 int width; 1041 int height; 1042 int depth; 1043 char *addr; 1044{ 1045 register PixmapPtr pPixmap; 1046 1047 pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth); 1048 if (!pPixmap) 1049 return NullPixmap; 1050 1051 if (!(*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth, 1052 BitsPerPixel(depth), PixmapBytePad(width, depth), (pointer)addr)) { 1053 (*pScreen->DestroyPixmap)(pPixmap); 1054 return NullPixmap; 1055 } 1056 return pPixmap; 1057} 1058 1059static int 1060ProcShmCreatePixmap(client) 1061 register ClientPtr client; 1062{ 1063 PixmapPtr pMap; 1064 DrawablePtr pDraw; 1065 DepthPtr pDepth; 1066 register int i, rc; 1067 ShmDescPtr shmdesc; 1068 REQUEST(xShmCreatePixmapReq); 1069 unsigned int width, height, depth; 1070 unsigned long size; 1071 1072 REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 1073 client->errorValue = stuff->pid; 1074 if (!sharedPixmaps) 1075 return BadImplementation; 1076 LEGAL_NEW_RESOURCE(stuff->pid, client); 1077 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, 1078 DixUnknownAccess); 1079 if (rc != Success) 1080 return rc; 1081 1082 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 1083 1084 width = stuff->width; 1085 height = stuff->height; 1086 depth = stuff->depth; 1087 if (!width || !height || !depth) 1088 { 1089 client->errorValue = 0; 1090 return BadValue; 1091 } 1092 if (width > 32767 || height > 32767) 1093 return BadAlloc; 1094 1095 if (stuff->depth != 1) 1096 { 1097 pDepth = pDraw->pScreen->allowedDepths; 1098 for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++) 1099 if (pDepth->depth == stuff->depth) 1100 goto CreatePmap; 1101 client->errorValue = stuff->depth; 1102 return BadValue; 1103 } 1104 1105CreatePmap: 1106 size = PixmapBytePad(width, depth) * height; 1107 if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { 1108 if (size < width * height) 1109 return BadAlloc; 1110 } 1111 /* thankfully, offset is unsigned */ 1112 if (stuff->offset + size < size) 1113 return BadAlloc; 1114 1115 VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); 1116 pMap = (*shmFuncs[pDraw->pScreen->myNum]->CreatePixmap)( 1117 pDraw->pScreen, stuff->width, 1118 stuff->height, stuff->depth, 1119 shmdesc->addr + stuff->offset); 1120 if (pMap) 1121 { 1122 pMap->devPrivates[shmPixmapPrivate].ptr = (pointer) shmdesc; 1123 shmdesc->refcnt++; 1124 pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 1125 pMap->drawable.id = stuff->pid; 1126 if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap)) 1127 { 1128 return(client->noClientException); 1129 } 1130 } 1131 return (BadAlloc); 1132} 1133 1134static int 1135ProcShmDispatch (client) 1136 register ClientPtr client; 1137{ 1138 REQUEST(xReq); 1139 switch (stuff->data) 1140 { 1141 case X_ShmQueryVersion: 1142 return ProcShmQueryVersion(client); 1143 case X_ShmAttach: 1144 return ProcShmAttach(client); 1145 case X_ShmDetach: 1146 return ProcShmDetach(client); 1147 case X_ShmPutImage: 1148#ifdef PANORAMIX 1149 if ( !noPanoramiXExtension ) 1150 return ProcPanoramiXShmPutImage(client); 1151#endif 1152 return ProcShmPutImage(client); 1153 case X_ShmGetImage: 1154#ifdef PANORAMIX 1155 if ( !noPanoramiXExtension ) 1156 return ProcPanoramiXShmGetImage(client); 1157#endif 1158 return ProcShmGetImage(client); 1159 case X_ShmCreatePixmap: 1160#ifdef PANORAMIX 1161 if ( !noPanoramiXExtension ) 1162 return ProcPanoramiXShmCreatePixmap(client); 1163#endif 1164 return ProcShmCreatePixmap(client); 1165 default: 1166 return BadRequest; 1167 } 1168} 1169 1170static void 1171SShmCompletionEvent(from, to) 1172 xShmCompletionEvent *from, *to; 1173{ 1174 to->type = from->type; 1175 cpswaps(from->sequenceNumber, to->sequenceNumber); 1176 cpswapl(from->drawable, to->drawable); 1177 cpswaps(from->minorEvent, to->minorEvent); 1178 to->majorEvent = from->majorEvent; 1179 cpswapl(from->shmseg, to->shmseg); 1180 cpswapl(from->offset, to->offset); 1181} 1182 1183static int 1184SProcShmQueryVersion(client) 1185 register ClientPtr client; 1186{ 1187 register int n; 1188 REQUEST(xShmQueryVersionReq); 1189 1190 swaps(&stuff->length, n); 1191 return ProcShmQueryVersion(client); 1192} 1193 1194static int 1195SProcShmAttach(client) 1196 ClientPtr client; 1197{ 1198 register int n; 1199 REQUEST(xShmAttachReq); 1200 swaps(&stuff->length, n); 1201 REQUEST_SIZE_MATCH(xShmAttachReq); 1202 swapl(&stuff->shmseg, n); 1203 swapl(&stuff->shmid, n); 1204 return ProcShmAttach(client); 1205} 1206 1207static int 1208SProcShmDetach(client) 1209 ClientPtr client; 1210{ 1211 register int n; 1212 REQUEST(xShmDetachReq); 1213 swaps(&stuff->length, n); 1214 REQUEST_SIZE_MATCH(xShmDetachReq); 1215 swapl(&stuff->shmseg, n); 1216 return ProcShmDetach(client); 1217} 1218 1219static int 1220SProcShmPutImage(client) 1221 ClientPtr client; 1222{ 1223 register int n; 1224 REQUEST(xShmPutImageReq); 1225 swaps(&stuff->length, n); 1226 REQUEST_SIZE_MATCH(xShmPutImageReq); 1227 swapl(&stuff->drawable, n); 1228 swapl(&stuff->gc, n); 1229 swaps(&stuff->totalWidth, n); 1230 swaps(&stuff->totalHeight, n); 1231 swaps(&stuff->srcX, n); 1232 swaps(&stuff->srcY, n); 1233 swaps(&stuff->srcWidth, n); 1234 swaps(&stuff->srcHeight, n); 1235 swaps(&stuff->dstX, n); 1236 swaps(&stuff->dstY, n); 1237 swapl(&stuff->shmseg, n); 1238 swapl(&stuff->offset, n); 1239 return ProcShmPutImage(client); 1240} 1241 1242static int 1243SProcShmGetImage(client) 1244 ClientPtr client; 1245{ 1246 register int n; 1247 REQUEST(xShmGetImageReq); 1248 swaps(&stuff->length, n); 1249 REQUEST_SIZE_MATCH(xShmGetImageReq); 1250 swapl(&stuff->drawable, n); 1251 swaps(&stuff->x, n); 1252 swaps(&stuff->y, n); 1253 swaps(&stuff->width, n); 1254 swaps(&stuff->height, n); 1255 swapl(&stuff->planeMask, n); 1256 swapl(&stuff->shmseg, n); 1257 swapl(&stuff->offset, n); 1258 return ProcShmGetImage(client); 1259} 1260 1261static int 1262SProcShmCreatePixmap(client) 1263 ClientPtr client; 1264{ 1265 register int n; 1266 REQUEST(xShmCreatePixmapReq); 1267 swaps(&stuff->length, n); 1268 REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 1269 swapl(&stuff->pid, n); 1270 swapl(&stuff->drawable, n); 1271 swaps(&stuff->width, n); 1272 swaps(&stuff->height, n); 1273 swapl(&stuff->shmseg, n); 1274 swapl(&stuff->offset, n); 1275 return ProcShmCreatePixmap(client); 1276} 1277 1278static int 1279SProcShmDispatch (client) 1280 register ClientPtr client; 1281{ 1282 REQUEST(xReq); 1283 switch (stuff->data) 1284 { 1285 case X_ShmQueryVersion: 1286 return SProcShmQueryVersion(client); 1287 case X_ShmAttach: 1288 return SProcShmAttach(client); 1289 case X_ShmDetach: 1290 return SProcShmDetach(client); 1291 case X_ShmPutImage: 1292 return SProcShmPutImage(client); 1293 case X_ShmGetImage: 1294 return SProcShmGetImage(client); 1295 case X_ShmCreatePixmap: 1296 return SProcShmCreatePixmap(client); 1297 default: 1298 return BadRequest; 1299 } 1300} 1301