1706f2543Smrg/************************************************************ 2706f2543Smrg 3706f2543SmrgCopyright 1989, 1998 The Open Group 4706f2543Smrg 5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its 6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that 7706f2543Smrgthe above copyright notice appear in all copies and that both that 8706f2543Smrgcopyright notice and this permission notice appear in supporting 9706f2543Smrgdocumentation. 10706f2543Smrg 11706f2543SmrgThe above copyright notice and this permission notice shall be included in 12706f2543Smrgall copies or substantial portions of the Software. 13706f2543Smrg 14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20706f2543Smrg 21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be 22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings 23706f2543Smrgin this Software without prior written authorization from The Open Group. 24706f2543Smrg 25706f2543Smrg********************************************************/ 26706f2543Smrg 27706f2543Smrg/* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */ 28706f2543Smrg 29706f2543Smrg 30706f2543Smrg#define SHM 31706f2543Smrg 32706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 33706f2543Smrg#include <dix-config.h> 34706f2543Smrg#endif 35706f2543Smrg 36706f2543Smrg#include <sys/types.h> 37706f2543Smrg#include <sys/ipc.h> 38706f2543Smrg#include <sys/shm.h> 39706f2543Smrg#include <unistd.h> 40706f2543Smrg#include <sys/stat.h> 41706f2543Smrg#include <X11/X.h> 42706f2543Smrg#include <X11/Xproto.h> 43706f2543Smrg#include "misc.h" 44706f2543Smrg#include "os.h" 45706f2543Smrg#include "dixstruct.h" 46706f2543Smrg#include "resource.h" 47706f2543Smrg#include "scrnintstr.h" 48706f2543Smrg#include "windowstr.h" 49706f2543Smrg#include "pixmapstr.h" 50706f2543Smrg#include "gcstruct.h" 51706f2543Smrg#include "extnsionst.h" 52706f2543Smrg#include "servermd.h" 53706f2543Smrg#include "shmint.h" 54706f2543Smrg#include "xace.h" 55706f2543Smrg#include <X11/extensions/shmproto.h> 56706f2543Smrg#include <X11/Xfuncproto.h> 57706f2543Smrg#include "protocol-versions.h" 58706f2543Smrg 59706f2543Smrg/* Needed for Solaris cross-zone shared memory extension */ 60706f2543Smrg#ifdef HAVE_SHMCTL64 61706f2543Smrg#include <sys/ipc_impl.h> 62706f2543Smrg#define SHMSTAT(id, buf) shmctl64(id, IPC_STAT64, buf) 63706f2543Smrg#define SHMSTAT_TYPE struct shmid_ds64 64706f2543Smrg#define SHMPERM_TYPE struct ipc_perm64 65706f2543Smrg#define SHM_PERM(buf) buf.shmx_perm 66706f2543Smrg#define SHM_SEGSZ(buf) buf.shmx_segsz 67706f2543Smrg#define SHMPERM_UID(p) p->ipcx_uid 68706f2543Smrg#define SHMPERM_CUID(p) p->ipcx_cuid 69706f2543Smrg#define SHMPERM_GID(p) p->ipcx_gid 70706f2543Smrg#define SHMPERM_CGID(p) p->ipcx_cgid 71706f2543Smrg#define SHMPERM_MODE(p) p->ipcx_mode 72706f2543Smrg#define SHMPERM_ZONEID(p) p->ipcx_zoneid 73706f2543Smrg#else 74706f2543Smrg#define SHMSTAT(id, buf) shmctl(id, IPC_STAT, buf) 75706f2543Smrg#define SHMSTAT_TYPE struct shmid_ds 76706f2543Smrg#define SHMPERM_TYPE struct ipc_perm 77706f2543Smrg#define SHM_PERM(buf) buf.shm_perm 78706f2543Smrg#define SHM_SEGSZ(buf) buf.shm_segsz 79706f2543Smrg#define SHMPERM_UID(p) p->uid 80706f2543Smrg#define SHMPERM_CUID(p) p->cuid 81706f2543Smrg#define SHMPERM_GID(p) p->gid 82706f2543Smrg#define SHMPERM_CGID(p) p->cgid 83706f2543Smrg#define SHMPERM_MODE(p) p->mode 84706f2543Smrg#endif 85706f2543Smrg 86706f2543Smrg#ifdef PANORAMIX 87706f2543Smrg#include "panoramiX.h" 88706f2543Smrg#include "panoramiXsrv.h" 89706f2543Smrg#endif 90706f2543Smrg 91706f2543Smrg#include "modinit.h" 92706f2543Smrg 93706f2543Smrgtypedef struct _ShmDesc { 94706f2543Smrg struct _ShmDesc *next; 95706f2543Smrg int shmid; 96706f2543Smrg int refcnt; 97706f2543Smrg char *addr; 98706f2543Smrg Bool writable; 99706f2543Smrg unsigned long size; 100706f2543Smrg} ShmDescRec, *ShmDescPtr; 101706f2543Smrg 102706f2543Smrgtypedef struct _ShmScrPrivateRec { 103706f2543Smrg CloseScreenProcPtr CloseScreen; 104706f2543Smrg ShmFuncsPtr shmFuncs; 105706f2543Smrg DestroyPixmapProcPtr destroyPixmap; 106706f2543Smrg} ShmScrPrivateRec; 107706f2543Smrg 108706f2543Smrgstatic PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS); 109706f2543Smrgstatic int ShmDetachSegment( 110706f2543Smrg pointer /* value */, 111706f2543Smrg XID /* shmseg */ 112706f2543Smrg ); 113706f2543Smrgstatic void ShmResetProc( 114706f2543Smrg ExtensionEntry * /* extEntry */ 115706f2543Smrg ); 116706f2543Smrgstatic void SShmCompletionEvent( 117706f2543Smrg xShmCompletionEvent * /* from */, 118706f2543Smrg xShmCompletionEvent * /* to */ 119706f2543Smrg ); 120706f2543Smrg 121706f2543Smrgstatic Bool ShmDestroyPixmap (PixmapPtr pPixmap); 122706f2543Smrg 123706f2543Smrg 124706f2543Smrgstatic unsigned char ShmReqCode; 125706f2543Smrgint ShmCompletionCode; 126706f2543Smrgint BadShmSegCode; 127706f2543SmrgRESTYPE ShmSegType; 128706f2543Smrgstatic ShmDescPtr Shmsegs; 129706f2543Smrgstatic Bool sharedPixmaps; 130706f2543Smrgstatic DevPrivateKeyRec shmScrPrivateKeyRec; 131706f2543Smrg#define shmScrPrivateKey (&shmScrPrivateKeyRec) 132706f2543Smrgstatic DevPrivateKeyRec shmPixmapPrivateKeyRec; 133706f2543Smrg#define shmPixmapPrivateKey (&shmPixmapPrivateKeyRec) 134706f2543Smrgstatic ShmFuncs miFuncs = {NULL, NULL}; 135706f2543Smrgstatic ShmFuncs fbFuncs = {fbShmCreatePixmap, NULL}; 136706f2543Smrg 137706f2543Smrg#define ShmGetScreenPriv(s) ((ShmScrPrivateRec *)dixLookupPrivate(&(s)->devPrivates, shmScrPrivateKey)) 138706f2543Smrg 139706f2543Smrg#define VERIFY_SHMSEG(shmseg,shmdesc,client) \ 140706f2543Smrg{ \ 141706f2543Smrg int rc; \ 142706f2543Smrg rc = dixLookupResourceByType((pointer *)&(shmdesc), shmseg, ShmSegType, \ 143706f2543Smrg client, DixReadAccess); \ 144706f2543Smrg if (rc != Success) \ 145706f2543Smrg return rc; \ 146706f2543Smrg} 147706f2543Smrg 148706f2543Smrg#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \ 149706f2543Smrg{ \ 150706f2543Smrg VERIFY_SHMSEG(shmseg, shmdesc, client); \ 151706f2543Smrg if ((offset & 3) || (offset > shmdesc->size)) \ 152706f2543Smrg { \ 153706f2543Smrg client->errorValue = offset; \ 154706f2543Smrg return BadValue; \ 155706f2543Smrg } \ 156706f2543Smrg if (needwrite && !shmdesc->writable) \ 157706f2543Smrg return BadAccess; \ 158706f2543Smrg} 159706f2543Smrg 160706f2543Smrg#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \ 161706f2543Smrg{ \ 162706f2543Smrg if ((offset + len) > shmdesc->size) \ 163706f2543Smrg { \ 164706f2543Smrg return BadAccess; \ 165706f2543Smrg } \ 166706f2543Smrg} 167706f2543Smrg 168706f2543Smrg 169706f2543Smrg#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__) 170706f2543Smrg#include <sys/signal.h> 171706f2543Smrg 172706f2543Smrgstatic Bool badSysCall = FALSE; 173706f2543Smrg 174706f2543Smrgstatic void 175706f2543SmrgSigSysHandler(int signo) 176706f2543Smrg{ 177706f2543Smrg badSysCall = TRUE; 178706f2543Smrg} 179706f2543Smrg 180706f2543Smrgstatic Bool CheckForShmSyscall(void) 181706f2543Smrg{ 182706f2543Smrg void (*oldHandler)(); 183706f2543Smrg int shmid = -1; 184706f2543Smrg 185706f2543Smrg /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */ 186706f2543Smrg oldHandler = signal(SIGSYS, SigSysHandler); 187706f2543Smrg 188706f2543Smrg badSysCall = FALSE; 189706f2543Smrg shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT); 190706f2543Smrg 191706f2543Smrg if (shmid != -1) 192706f2543Smrg { 193706f2543Smrg /* Successful allocation - clean up */ 194706f2543Smrg shmctl(shmid, IPC_RMID, NULL); 195706f2543Smrg } 196706f2543Smrg else 197706f2543Smrg { 198706f2543Smrg /* Allocation failed */ 199706f2543Smrg badSysCall = TRUE; 200706f2543Smrg } 201706f2543Smrg signal(SIGSYS, oldHandler); 202706f2543Smrg return !badSysCall; 203706f2543Smrg} 204706f2543Smrg 205706f2543Smrg#define MUST_CHECK_FOR_SHM_SYSCALL 206706f2543Smrg 207706f2543Smrg#endif 208706f2543Smrg 209706f2543Smrgstatic Bool 210706f2543SmrgShmCloseScreen(int i, ScreenPtr pScreen) 211706f2543Smrg{ 212706f2543Smrg ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); 213706f2543Smrg pScreen->CloseScreen = screen_priv->CloseScreen; 214706f2543Smrg dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL); 215706f2543Smrg free(screen_priv); 216706f2543Smrg return (*pScreen->CloseScreen) (i, pScreen); 217706f2543Smrg} 218706f2543Smrg 219706f2543Smrgstatic ShmScrPrivateRec * 220706f2543SmrgShmInitScreenPriv(ScreenPtr pScreen) 221706f2543Smrg{ 222706f2543Smrg ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); 223706f2543Smrg if (!screen_priv) 224706f2543Smrg { 225706f2543Smrg screen_priv = calloc(1, sizeof (ShmScrPrivateRec)); 226706f2543Smrg screen_priv->CloseScreen = pScreen->CloseScreen; 227706f2543Smrg dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv); 228706f2543Smrg pScreen->CloseScreen = ShmCloseScreen; 229706f2543Smrg } 230706f2543Smrg return screen_priv; 231706f2543Smrg} 232706f2543Smrg 233706f2543Smrgstatic Bool 234706f2543SmrgShmRegisterPrivates(void) 235706f2543Smrg{ 236706f2543Smrg if (!dixRegisterPrivateKey(&shmScrPrivateKeyRec, PRIVATE_SCREEN, 0)) 237706f2543Smrg return FALSE; 238706f2543Smrg if (!dixRegisterPrivateKey(&shmPixmapPrivateKeyRec, PRIVATE_PIXMAP, 0)) 239706f2543Smrg return FALSE; 240706f2543Smrg return TRUE; 241706f2543Smrg} 242706f2543Smrg 243706f2543Smrg/*ARGSUSED*/ 244706f2543Smrgstatic void 245706f2543SmrgShmResetProc(ExtensionEntry *extEntry) 246706f2543Smrg{ 247706f2543Smrg int i; 248706f2543Smrg for (i = 0; i < screenInfo.numScreens; i++) 249706f2543Smrg ShmRegisterFuncs(screenInfo.screens[i], NULL); 250706f2543Smrg} 251706f2543Smrg 252706f2543Smrgvoid 253706f2543SmrgShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs) 254706f2543Smrg{ 255706f2543Smrg if (!ShmRegisterPrivates()) 256706f2543Smrg return; 257706f2543Smrg ShmInitScreenPriv(pScreen)->shmFuncs = funcs; 258706f2543Smrg} 259706f2543Smrg 260706f2543Smrgstatic Bool 261706f2543SmrgShmDestroyPixmap (PixmapPtr pPixmap) 262706f2543Smrg{ 263706f2543Smrg ScreenPtr pScreen = pPixmap->drawable.pScreen; 264706f2543Smrg ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); 265706f2543Smrg Bool ret; 266706f2543Smrg if (pPixmap->refcnt == 1) 267706f2543Smrg { 268706f2543Smrg ShmDescPtr shmdesc; 269706f2543Smrg shmdesc = (ShmDescPtr)dixLookupPrivate(&pPixmap->devPrivates, 270706f2543Smrg shmPixmapPrivateKey); 271706f2543Smrg if (shmdesc) 272706f2543Smrg ShmDetachSegment ((pointer) shmdesc, pPixmap->drawable.id); 273706f2543Smrg } 274706f2543Smrg 275706f2543Smrg pScreen->DestroyPixmap = screen_priv->destroyPixmap; 276706f2543Smrg ret = (*pScreen->DestroyPixmap) (pPixmap); 277706f2543Smrg screen_priv->destroyPixmap = pScreen->DestroyPixmap; 278706f2543Smrg pScreen->DestroyPixmap = ShmDestroyPixmap; 279706f2543Smrg return ret; 280706f2543Smrg} 281706f2543Smrg 282706f2543Smrgvoid 283706f2543SmrgShmRegisterFbFuncs(ScreenPtr pScreen) 284706f2543Smrg{ 285706f2543Smrg ShmRegisterFuncs(pScreen, &fbFuncs); 286706f2543Smrg} 287706f2543Smrg 288706f2543Smrgstatic int 289706f2543SmrgProcShmQueryVersion(ClientPtr client) 290706f2543Smrg{ 291706f2543Smrg xShmQueryVersionReply rep; 292706f2543Smrg int n; 293706f2543Smrg 294706f2543Smrg REQUEST_SIZE_MATCH(xShmQueryVersionReq); 295706f2543Smrg memset(&rep, 0, sizeof(xShmQueryVersionReply)); 296706f2543Smrg rep.type = X_Reply; 297706f2543Smrg rep.length = 0; 298706f2543Smrg rep.sequenceNumber = client->sequence; 299706f2543Smrg rep.sharedPixmaps = sharedPixmaps; 300706f2543Smrg rep.pixmapFormat = sharedPixmaps ? ZPixmap : 0; 301706f2543Smrg rep.majorVersion = SERVER_SHM_MAJOR_VERSION; 302706f2543Smrg rep.minorVersion = SERVER_SHM_MINOR_VERSION; 303706f2543Smrg rep.uid = geteuid(); 304706f2543Smrg rep.gid = getegid(); 305706f2543Smrg if (client->swapped) { 306706f2543Smrg swaps(&rep.sequenceNumber, n); 307706f2543Smrg swapl(&rep.length, n); 308706f2543Smrg swaps(&rep.majorVersion, n); 309706f2543Smrg swaps(&rep.minorVersion, n); 310706f2543Smrg swaps(&rep.uid, n); 311706f2543Smrg swaps(&rep.gid, n); 312706f2543Smrg } 313706f2543Smrg WriteToClient(client, sizeof(xShmQueryVersionReply), (char *)&rep); 314706f2543Smrg return Success; 315706f2543Smrg} 316706f2543Smrg 317706f2543Smrg/* 318706f2543Smrg * Simulate the access() system call for a shared memory segement, 319706f2543Smrg * using the credentials from the client if available 320706f2543Smrg */ 321706f2543Smrgstatic int 322706f2543Smrgshm_access(ClientPtr client, SHMPERM_TYPE *perm, int readonly) 323706f2543Smrg{ 324706f2543Smrg int uid, gid; 325706f2543Smrg mode_t mask; 326706f2543Smrg int uidset = 0, gidset = 0; 327706f2543Smrg LocalClientCredRec *lcc; 328706f2543Smrg 329706f2543Smrg if (GetLocalClientCreds(client, &lcc) != -1) { 330706f2543Smrg 331706f2543Smrg if (lcc->fieldsSet & LCC_UID_SET) { 332706f2543Smrg uid = lcc->euid; 333706f2543Smrg uidset = 1; 334706f2543Smrg } 335706f2543Smrg if (lcc->fieldsSet & LCC_GID_SET) { 336706f2543Smrg gid = lcc->egid; 337706f2543Smrg gidset = 1; 338706f2543Smrg } 339706f2543Smrg 340706f2543Smrg#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID) 341706f2543Smrg if ( ((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1) 342706f2543Smrg || (lcc->zoneid != SHMPERM_ZONEID(perm))) { 343706f2543Smrg uidset = 0; 344706f2543Smrg gidset = 0; 345706f2543Smrg } 346706f2543Smrg#endif 347706f2543Smrg FreeLocalClientCreds(lcc); 348706f2543Smrg 349706f2543Smrg if (uidset) { 350706f2543Smrg /* User id 0 always gets access */ 351706f2543Smrg if (uid == 0) { 352706f2543Smrg return 0; 353706f2543Smrg } 354706f2543Smrg /* Check the owner */ 355706f2543Smrg if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) { 356706f2543Smrg mask = S_IRUSR; 357706f2543Smrg if (!readonly) { 358706f2543Smrg mask |= S_IWUSR; 359706f2543Smrg } 360706f2543Smrg return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; 361706f2543Smrg } 362706f2543Smrg } 363706f2543Smrg 364706f2543Smrg if (gidset) { 365706f2543Smrg /* Check the group */ 366706f2543Smrg if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) { 367706f2543Smrg mask = S_IRGRP; 368706f2543Smrg if (!readonly) { 369706f2543Smrg mask |= S_IWGRP; 370706f2543Smrg } 371706f2543Smrg return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; 372706f2543Smrg } 373706f2543Smrg } 374706f2543Smrg } 375706f2543Smrg /* Otherwise, check everyone else */ 376706f2543Smrg mask = S_IROTH; 377706f2543Smrg if (!readonly) { 378706f2543Smrg mask |= S_IWOTH; 379706f2543Smrg } 380706f2543Smrg return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; 381706f2543Smrg} 382706f2543Smrg 383706f2543Smrgstatic int 384706f2543SmrgProcShmAttach(ClientPtr client) 385706f2543Smrg{ 386706f2543Smrg SHMSTAT_TYPE buf; 387706f2543Smrg ShmDescPtr shmdesc; 388706f2543Smrg REQUEST(xShmAttachReq); 389706f2543Smrg 390706f2543Smrg REQUEST_SIZE_MATCH(xShmAttachReq); 391706f2543Smrg LEGAL_NEW_RESOURCE(stuff->shmseg, client); 392706f2543Smrg if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) 393706f2543Smrg { 394706f2543Smrg client->errorValue = stuff->readOnly; 395706f2543Smrg return BadValue; 396706f2543Smrg } 397706f2543Smrg for (shmdesc = Shmsegs; 398706f2543Smrg shmdesc && (shmdesc->shmid != stuff->shmid); 399706f2543Smrg shmdesc = shmdesc->next) 400706f2543Smrg ; 401706f2543Smrg if (shmdesc) 402706f2543Smrg { 403706f2543Smrg if (!stuff->readOnly && !shmdesc->writable) 404706f2543Smrg return BadAccess; 405706f2543Smrg shmdesc->refcnt++; 406706f2543Smrg } 407706f2543Smrg else 408706f2543Smrg { 409706f2543Smrg shmdesc = malloc(sizeof(ShmDescRec)); 410706f2543Smrg if (!shmdesc) 411706f2543Smrg return BadAlloc; 412706f2543Smrg shmdesc->addr = shmat(stuff->shmid, 0, 413706f2543Smrg stuff->readOnly ? SHM_RDONLY : 0); 414706f2543Smrg if ((shmdesc->addr == ((char *)-1)) || 415706f2543Smrg SHMSTAT(stuff->shmid, &buf)) 416706f2543Smrg { 417706f2543Smrg free(shmdesc); 418706f2543Smrg return BadAccess; 419706f2543Smrg } 420706f2543Smrg 421706f2543Smrg /* The attach was performed with root privs. We must 422706f2543Smrg * do manual checking of access rights for the credentials 423706f2543Smrg * of the client */ 424706f2543Smrg 425706f2543Smrg if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) { 426706f2543Smrg shmdt(shmdesc->addr); 427706f2543Smrg free(shmdesc); 428706f2543Smrg return BadAccess; 429706f2543Smrg } 430706f2543Smrg 431706f2543Smrg shmdesc->shmid = stuff->shmid; 432706f2543Smrg shmdesc->refcnt = 1; 433706f2543Smrg shmdesc->writable = !stuff->readOnly; 434706f2543Smrg shmdesc->size = SHM_SEGSZ(buf); 435706f2543Smrg shmdesc->next = Shmsegs; 436706f2543Smrg Shmsegs = shmdesc; 437706f2543Smrg } 438706f2543Smrg if (!AddResource(stuff->shmseg, ShmSegType, (pointer)shmdesc)) 439706f2543Smrg return BadAlloc; 440706f2543Smrg return Success; 441706f2543Smrg} 442706f2543Smrg 443706f2543Smrg/*ARGSUSED*/ 444706f2543Smrgstatic int 445706f2543SmrgShmDetachSegment(pointer value, /* must conform to DeleteType */ 446706f2543Smrg XID shmseg) 447706f2543Smrg{ 448706f2543Smrg ShmDescPtr shmdesc = (ShmDescPtr)value; 449706f2543Smrg ShmDescPtr *prev; 450706f2543Smrg 451706f2543Smrg if (--shmdesc->refcnt) 452706f2543Smrg return TRUE; 453706f2543Smrg shmdt(shmdesc->addr); 454706f2543Smrg for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next) 455706f2543Smrg ; 456706f2543Smrg *prev = shmdesc->next; 457706f2543Smrg free(shmdesc); 458706f2543Smrg return Success; 459706f2543Smrg} 460706f2543Smrg 461706f2543Smrgstatic int 462706f2543SmrgProcShmDetach(ClientPtr client) 463706f2543Smrg{ 464706f2543Smrg ShmDescPtr shmdesc; 465706f2543Smrg REQUEST(xShmDetachReq); 466706f2543Smrg 467706f2543Smrg REQUEST_SIZE_MATCH(xShmDetachReq); 468706f2543Smrg VERIFY_SHMSEG(stuff->shmseg, shmdesc, client); 469706f2543Smrg FreeResource(stuff->shmseg, RT_NONE); 470706f2543Smrg return Success; 471706f2543Smrg} 472706f2543Smrg 473706f2543Smrg/* 474706f2543Smrg * If the given request doesn't exactly match PutImage's constraints, 475706f2543Smrg * wrap the image in a scratch pixmap header and let CopyArea sort it out. 476706f2543Smrg */ 477706f2543Smrgstatic void 478706f2543SmrgdoShmPutImage(DrawablePtr dst, GCPtr pGC, 479706f2543Smrg int depth, unsigned int format, 480706f2543Smrg int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, 481706f2543Smrg char *data) 482706f2543Smrg{ 483706f2543Smrg PixmapPtr pPixmap; 484706f2543Smrg 485706f2543Smrg if (format == ZPixmap || (format == XYPixmap && depth == 1)) { 486706f2543Smrg pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth, 487706f2543Smrg BitsPerPixel(depth), 488706f2543Smrg PixmapBytePad(w, depth), 489706f2543Smrg data); 490706f2543Smrg if (!pPixmap) 491706f2543Smrg return; 492706f2543Smrg pGC->ops->CopyArea((DrawablePtr)pPixmap, dst, pGC, sx, sy, sw, sh, dx, dy); 493706f2543Smrg FreeScratchPixmapHeader(pPixmap); 494706f2543Smrg } else { 495706f2543Smrg GCPtr putGC = GetScratchGC(depth, dst->pScreen); 496706f2543Smrg 497706f2543Smrg if (!putGC) 498706f2543Smrg return; 499706f2543Smrg 500706f2543Smrg pPixmap = (*dst->pScreen->CreatePixmap)(dst->pScreen, sw, sh, depth, 501706f2543Smrg CREATE_PIXMAP_USAGE_SCRATCH); 502706f2543Smrg if (!pPixmap) { 503706f2543Smrg FreeScratchGC(putGC); 504706f2543Smrg return; 505706f2543Smrg } 506706f2543Smrg ValidateGC(&pPixmap->drawable, putGC); 507706f2543Smrg (*putGC->ops->PutImage)(&pPixmap->drawable, putGC, depth, -sx, -sy, w, h, 0, 508706f2543Smrg (format == XYPixmap) ? XYPixmap : ZPixmap, data); 509706f2543Smrg FreeScratchGC(putGC); 510706f2543Smrg if (format == XYBitmap) 511706f2543Smrg (void)(*pGC->ops->CopyPlane)(&pPixmap->drawable, dst, pGC, 0, 0, sw, sh, 512706f2543Smrg dx, dy, 1L); 513706f2543Smrg else 514706f2543Smrg (void)(*pGC->ops->CopyArea)(&pPixmap->drawable, dst, pGC, 0, 0, sw, sh, 515706f2543Smrg dx, dy); 516706f2543Smrg (*pPixmap->drawable.pScreen->DestroyPixmap)(pPixmap); 517706f2543Smrg } 518706f2543Smrg} 519706f2543Smrg 520706f2543Smrgstatic int 521706f2543SmrgProcShmPutImage(ClientPtr client) 522706f2543Smrg{ 523706f2543Smrg GCPtr pGC; 524706f2543Smrg DrawablePtr pDraw; 525706f2543Smrg long length; 526706f2543Smrg ShmDescPtr shmdesc; 527706f2543Smrg REQUEST(xShmPutImageReq); 528706f2543Smrg 529706f2543Smrg REQUEST_SIZE_MATCH(xShmPutImageReq); 530706f2543Smrg VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); 531706f2543Smrg VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client); 532706f2543Smrg if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse)) 533706f2543Smrg return BadValue; 534706f2543Smrg if (stuff->format == XYBitmap) 535706f2543Smrg { 536706f2543Smrg if (stuff->depth != 1) 537706f2543Smrg return BadMatch; 538706f2543Smrg length = PixmapBytePad(stuff->totalWidth, 1); 539706f2543Smrg } 540706f2543Smrg else if (stuff->format == XYPixmap) 541706f2543Smrg { 542706f2543Smrg if (pDraw->depth != stuff->depth) 543706f2543Smrg return BadMatch; 544706f2543Smrg length = PixmapBytePad(stuff->totalWidth, 1); 545706f2543Smrg length *= stuff->depth; 546706f2543Smrg } 547706f2543Smrg else if (stuff->format == ZPixmap) 548706f2543Smrg { 549706f2543Smrg if (pDraw->depth != stuff->depth) 550706f2543Smrg return BadMatch; 551706f2543Smrg length = PixmapBytePad(stuff->totalWidth, stuff->depth); 552706f2543Smrg } 553706f2543Smrg else 554706f2543Smrg { 555706f2543Smrg client->errorValue = stuff->format; 556706f2543Smrg return BadValue; 557706f2543Smrg } 558706f2543Smrg 559706f2543Smrg /* 560706f2543Smrg * There's a potential integer overflow in this check: 561706f2543Smrg * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight, 562706f2543Smrg * client); 563706f2543Smrg * the version below ought to avoid it 564706f2543Smrg */ 565706f2543Smrg if (stuff->totalHeight != 0 && 566706f2543Smrg length > (shmdesc->size - stuff->offset)/stuff->totalHeight) { 567706f2543Smrg client->errorValue = stuff->totalWidth; 568706f2543Smrg return BadValue; 569706f2543Smrg } 570706f2543Smrg if (stuff->srcX > stuff->totalWidth) 571706f2543Smrg { 572706f2543Smrg client->errorValue = stuff->srcX; 573706f2543Smrg return BadValue; 574706f2543Smrg } 575706f2543Smrg if (stuff->srcY > stuff->totalHeight) 576706f2543Smrg { 577706f2543Smrg client->errorValue = stuff->srcY; 578706f2543Smrg return BadValue; 579706f2543Smrg } 580706f2543Smrg if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) 581706f2543Smrg { 582706f2543Smrg client->errorValue = stuff->srcWidth; 583706f2543Smrg return BadValue; 584706f2543Smrg } 585706f2543Smrg if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) 586706f2543Smrg { 587706f2543Smrg client->errorValue = stuff->srcHeight; 588706f2543Smrg return BadValue; 589706f2543Smrg } 590706f2543Smrg 591706f2543Smrg if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) || 592706f2543Smrg ((stuff->format != ZPixmap) && 593706f2543Smrg (stuff->srcX < screenInfo.bitmapScanlinePad) && 594706f2543Smrg ((stuff->format == XYBitmap) || 595706f2543Smrg ((stuff->srcY == 0) && 596706f2543Smrg (stuff->srcHeight == stuff->totalHeight))))) && 597706f2543Smrg ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth)) 598706f2543Smrg (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, 599706f2543Smrg stuff->dstX, stuff->dstY, 600706f2543Smrg stuff->totalWidth, stuff->srcHeight, 601706f2543Smrg stuff->srcX, stuff->format, 602706f2543Smrg shmdesc->addr + stuff->offset + 603706f2543Smrg (stuff->srcY * length)); 604706f2543Smrg else 605706f2543Smrg doShmPutImage(pDraw, pGC, stuff->depth, stuff->format, 606706f2543Smrg stuff->totalWidth, stuff->totalHeight, 607706f2543Smrg stuff->srcX, stuff->srcY, 608706f2543Smrg stuff->srcWidth, stuff->srcHeight, 609706f2543Smrg stuff->dstX, stuff->dstY, 610706f2543Smrg shmdesc->addr + stuff->offset); 611706f2543Smrg 612706f2543Smrg if (stuff->sendEvent) 613706f2543Smrg { 614706f2543Smrg xShmCompletionEvent ev; 615706f2543Smrg 616706f2543Smrg ev.type = ShmCompletionCode; 617706f2543Smrg ev.drawable = stuff->drawable; 618706f2543Smrg ev.minorEvent = X_ShmPutImage; 619706f2543Smrg ev.majorEvent = ShmReqCode; 620706f2543Smrg ev.shmseg = stuff->shmseg; 621706f2543Smrg ev.offset = stuff->offset; 622706f2543Smrg WriteEventsToClient(client, 1, (xEvent *) &ev); 623706f2543Smrg } 624706f2543Smrg 625706f2543Smrg return Success; 626706f2543Smrg} 627706f2543Smrg 628706f2543Smrgstatic int 629706f2543SmrgProcShmGetImage(ClientPtr client) 630706f2543Smrg{ 631706f2543Smrg DrawablePtr pDraw; 632706f2543Smrg long lenPer = 0, length; 633706f2543Smrg Mask plane = 0; 634706f2543Smrg xShmGetImageReply xgi; 635706f2543Smrg ShmDescPtr shmdesc; 636706f2543Smrg int n, rc; 637706f2543Smrg 638706f2543Smrg REQUEST(xShmGetImageReq); 639706f2543Smrg 640706f2543Smrg REQUEST_SIZE_MATCH(xShmGetImageReq); 641706f2543Smrg if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) 642706f2543Smrg { 643706f2543Smrg client->errorValue = stuff->format; 644706f2543Smrg return BadValue; 645706f2543Smrg } 646706f2543Smrg rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, 647706f2543Smrg DixReadAccess); 648706f2543Smrg if (rc != Success) 649706f2543Smrg return rc; 650706f2543Smrg VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 651706f2543Smrg if (pDraw->type == DRAWABLE_WINDOW) 652706f2543Smrg { 653706f2543Smrg if( /* check for being viewable */ 654706f2543Smrg !((WindowPtr) pDraw)->realized || 655706f2543Smrg /* check for being on screen */ 656706f2543Smrg pDraw->x + stuff->x < 0 || 657706f2543Smrg pDraw->x + stuff->x + (int)stuff->width > pDraw->pScreen->width || 658706f2543Smrg pDraw->y + stuff->y < 0 || 659706f2543Smrg pDraw->y + stuff->y + (int)stuff->height > pDraw->pScreen->height || 660706f2543Smrg /* check for being inside of border */ 661706f2543Smrg stuff->x < - wBorderWidth((WindowPtr)pDraw) || 662706f2543Smrg stuff->x + (int)stuff->width > 663706f2543Smrg wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || 664706f2543Smrg stuff->y < -wBorderWidth((WindowPtr)pDraw) || 665706f2543Smrg stuff->y + (int)stuff->height > 666706f2543Smrg wBorderWidth((WindowPtr)pDraw) + (int)pDraw->height 667706f2543Smrg ) 668706f2543Smrg return BadMatch; 669706f2543Smrg xgi.visual = wVisual(((WindowPtr)pDraw)); 670706f2543Smrg } 671706f2543Smrg else 672706f2543Smrg { 673706f2543Smrg if (stuff->x < 0 || 674706f2543Smrg stuff->x+(int)stuff->width > pDraw->width || 675706f2543Smrg stuff->y < 0 || 676706f2543Smrg stuff->y+(int)stuff->height > pDraw->height 677706f2543Smrg ) 678706f2543Smrg return BadMatch; 679706f2543Smrg xgi.visual = None; 680706f2543Smrg } 681706f2543Smrg xgi.type = X_Reply; 682706f2543Smrg xgi.length = 0; 683706f2543Smrg xgi.sequenceNumber = client->sequence; 684706f2543Smrg xgi.depth = pDraw->depth; 685706f2543Smrg if(stuff->format == ZPixmap) 686706f2543Smrg { 687706f2543Smrg length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height; 688706f2543Smrg } 689706f2543Smrg else 690706f2543Smrg { 691706f2543Smrg lenPer = PixmapBytePad(stuff->width, 1) * stuff->height; 692706f2543Smrg plane = ((Mask)1) << (pDraw->depth - 1); 693706f2543Smrg /* only planes asked for */ 694706f2543Smrg length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1))); 695706f2543Smrg } 696706f2543Smrg 697706f2543Smrg VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); 698706f2543Smrg xgi.size = length; 699706f2543Smrg 700706f2543Smrg if (length == 0) 701706f2543Smrg { 702706f2543Smrg /* nothing to do */ 703706f2543Smrg } 704706f2543Smrg else if (stuff->format == ZPixmap) 705706f2543Smrg { 706706f2543Smrg (*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y, 707706f2543Smrg stuff->width, stuff->height, 708706f2543Smrg stuff->format, stuff->planeMask, 709706f2543Smrg shmdesc->addr + stuff->offset); 710706f2543Smrg } 711706f2543Smrg else 712706f2543Smrg { 713706f2543Smrg 714706f2543Smrg length = stuff->offset; 715706f2543Smrg for (; plane; plane >>= 1) 716706f2543Smrg { 717706f2543Smrg if (stuff->planeMask & plane) 718706f2543Smrg { 719706f2543Smrg (*pDraw->pScreen->GetImage)(pDraw, 720706f2543Smrg stuff->x, stuff->y, 721706f2543Smrg stuff->width, stuff->height, 722706f2543Smrg stuff->format, plane, 723706f2543Smrg shmdesc->addr + length); 724706f2543Smrg length += lenPer; 725706f2543Smrg } 726706f2543Smrg } 727706f2543Smrg } 728706f2543Smrg 729706f2543Smrg if (client->swapped) { 730706f2543Smrg swaps(&xgi.sequenceNumber, n); 731706f2543Smrg swapl(&xgi.length, n); 732706f2543Smrg swapl(&xgi.visual, n); 733706f2543Smrg swapl(&xgi.size, n); 734706f2543Smrg } 735706f2543Smrg WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); 736706f2543Smrg 737706f2543Smrg return Success; 738706f2543Smrg} 739706f2543Smrg 740706f2543Smrg#ifdef PANORAMIX 741706f2543Smrgstatic int 742706f2543SmrgProcPanoramiXShmPutImage(ClientPtr client) 743706f2543Smrg{ 744706f2543Smrg int j, result, orig_x, orig_y; 745706f2543Smrg PanoramiXRes *draw, *gc; 746706f2543Smrg Bool sendEvent, isRoot; 747706f2543Smrg 748706f2543Smrg REQUEST(xShmPutImageReq); 749706f2543Smrg REQUEST_SIZE_MATCH(xShmPutImageReq); 750706f2543Smrg 751706f2543Smrg result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, 752706f2543Smrg XRC_DRAWABLE, client, DixWriteAccess); 753706f2543Smrg if (result != Success) 754706f2543Smrg return (result == BadValue) ? BadDrawable : result; 755706f2543Smrg 756706f2543Smrg result = dixLookupResourceByType((pointer *)&gc, stuff->gc, 757706f2543Smrg XRT_GC, client, DixReadAccess); 758706f2543Smrg if (result != Success) 759706f2543Smrg return result; 760706f2543Smrg 761706f2543Smrg isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; 762706f2543Smrg 763706f2543Smrg orig_x = stuff->dstX; 764706f2543Smrg orig_y = stuff->dstY; 765706f2543Smrg sendEvent = stuff->sendEvent; 766706f2543Smrg stuff->sendEvent = 0; 767706f2543Smrg FOR_NSCREENS(j) { 768706f2543Smrg if(!j) stuff->sendEvent = sendEvent; 769706f2543Smrg stuff->drawable = draw->info[j].id; 770706f2543Smrg stuff->gc = gc->info[j].id; 771706f2543Smrg if (isRoot) { 772706f2543Smrg stuff->dstX = orig_x - screenInfo.screens[j]->x; 773706f2543Smrg stuff->dstY = orig_y - screenInfo.screens[j]->y; 774706f2543Smrg } 775706f2543Smrg result = ProcShmPutImage(client); 776706f2543Smrg if(result != Success) break; 777706f2543Smrg } 778706f2543Smrg return result; 779706f2543Smrg} 780706f2543Smrg 781706f2543Smrgstatic int 782706f2543SmrgProcPanoramiXShmGetImage(ClientPtr client) 783706f2543Smrg{ 784706f2543Smrg PanoramiXRes *draw; 785706f2543Smrg DrawablePtr *drawables; 786706f2543Smrg DrawablePtr pDraw; 787706f2543Smrg xShmGetImageReply xgi; 788706f2543Smrg ShmDescPtr shmdesc; 789706f2543Smrg int i, x, y, w, h, format, rc; 790706f2543Smrg Mask plane = 0, planemask; 791706f2543Smrg long lenPer = 0, length, widthBytesLine; 792706f2543Smrg Bool isRoot; 793706f2543Smrg 794706f2543Smrg REQUEST(xShmGetImageReq); 795706f2543Smrg 796706f2543Smrg REQUEST_SIZE_MATCH(xShmGetImageReq); 797706f2543Smrg 798706f2543Smrg if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) { 799706f2543Smrg client->errorValue = stuff->format; 800706f2543Smrg return BadValue; 801706f2543Smrg } 802706f2543Smrg 803706f2543Smrg rc = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, 804706f2543Smrg XRC_DRAWABLE, client, DixWriteAccess); 805706f2543Smrg if (rc != Success) 806706f2543Smrg return (rc == BadValue) ? BadDrawable : rc; 807706f2543Smrg 808706f2543Smrg if (draw->type == XRT_PIXMAP) 809706f2543Smrg return ProcShmGetImage(client); 810706f2543Smrg 811706f2543Smrg rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, 812706f2543Smrg DixReadAccess); 813706f2543Smrg if (rc != Success) 814706f2543Smrg return rc; 815706f2543Smrg 816706f2543Smrg VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 817706f2543Smrg 818706f2543Smrg x = stuff->x; 819706f2543Smrg y = stuff->y; 820706f2543Smrg w = stuff->width; 821706f2543Smrg h = stuff->height; 822706f2543Smrg format = stuff->format; 823706f2543Smrg planemask = stuff->planeMask; 824706f2543Smrg 825706f2543Smrg isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; 826706f2543Smrg 827706f2543Smrg if(isRoot) { 828706f2543Smrg if( /* check for being onscreen */ 829706f2543Smrg x < 0 || x + w > PanoramiXPixWidth || 830706f2543Smrg y < 0 || y + h > PanoramiXPixHeight ) 831706f2543Smrg return BadMatch; 832706f2543Smrg } else { 833706f2543Smrg if( /* check for being onscreen */ 834706f2543Smrg screenInfo.screens[0]->x + pDraw->x + x < 0 || 835706f2543Smrg screenInfo.screens[0]->x + pDraw->x + x + w > PanoramiXPixWidth || 836706f2543Smrg screenInfo.screens[0]->y + pDraw->y + y < 0 || 837706f2543Smrg screenInfo.screens[0]->y + pDraw->y + y + h > PanoramiXPixHeight || 838706f2543Smrg /* check for being inside of border */ 839706f2543Smrg x < - wBorderWidth((WindowPtr)pDraw) || 840706f2543Smrg x + w > wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || 841706f2543Smrg y < -wBorderWidth((WindowPtr)pDraw) || 842706f2543Smrg y + h > wBorderWidth ((WindowPtr)pDraw) + (int)pDraw->height) 843706f2543Smrg return BadMatch; 844706f2543Smrg } 845706f2543Smrg 846706f2543Smrg drawables = calloc(PanoramiXNumScreens, sizeof(DrawablePtr)); 847706f2543Smrg if(!drawables) 848706f2543Smrg return BadAlloc; 849706f2543Smrg 850706f2543Smrg drawables[0] = pDraw; 851706f2543Smrg for(i = 1; i < PanoramiXNumScreens; i++) { 852706f2543Smrg rc = dixLookupDrawable(drawables+i, draw->info[i].id, client, 0, 853706f2543Smrg DixReadAccess); 854706f2543Smrg if (rc != Success) 855706f2543Smrg { 856706f2543Smrg free(drawables); 857706f2543Smrg return rc; 858706f2543Smrg } 859706f2543Smrg } 860706f2543Smrg 861706f2543Smrg xgi.visual = wVisual(((WindowPtr)pDraw)); 862706f2543Smrg xgi.type = X_Reply; 863706f2543Smrg xgi.length = 0; 864706f2543Smrg xgi.sequenceNumber = client->sequence; 865706f2543Smrg xgi.depth = pDraw->depth; 866706f2543Smrg 867706f2543Smrg if(format == ZPixmap) { 868706f2543Smrg widthBytesLine = PixmapBytePad(w, pDraw->depth); 869706f2543Smrg length = widthBytesLine * h; 870706f2543Smrg } else { 871706f2543Smrg widthBytesLine = PixmapBytePad(w, 1); 872706f2543Smrg lenPer = widthBytesLine * h; 873706f2543Smrg plane = ((Mask)1) << (pDraw->depth - 1); 874706f2543Smrg length = lenPer * Ones(planemask & (plane | (plane - 1))); 875706f2543Smrg } 876706f2543Smrg 877706f2543Smrg VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); 878706f2543Smrg xgi.size = length; 879706f2543Smrg 880706f2543Smrg if (length == 0) {/* nothing to do */ } 881706f2543Smrg else if (format == ZPixmap) { 882706f2543Smrg XineramaGetImageData(drawables, x, y, w, h, format, planemask, 883706f2543Smrg shmdesc->addr + stuff->offset, 884706f2543Smrg widthBytesLine, isRoot); 885706f2543Smrg } else { 886706f2543Smrg 887706f2543Smrg length = stuff->offset; 888706f2543Smrg for (; plane; plane >>= 1) { 889706f2543Smrg if (planemask & plane) { 890706f2543Smrg XineramaGetImageData(drawables, x, y, w, h, 891706f2543Smrg format, plane, shmdesc->addr + length, 892706f2543Smrg widthBytesLine, isRoot); 893706f2543Smrg length += lenPer; 894706f2543Smrg } 895706f2543Smrg } 896706f2543Smrg } 897706f2543Smrg free(drawables); 898706f2543Smrg 899706f2543Smrg if (client->swapped) { 900706f2543Smrg int n; 901706f2543Smrg swaps(&xgi.sequenceNumber, n); 902706f2543Smrg swapl(&xgi.length, n); 903706f2543Smrg swapl(&xgi.visual, n); 904706f2543Smrg swapl(&xgi.size, n); 905706f2543Smrg } 906706f2543Smrg WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); 907706f2543Smrg 908706f2543Smrg return Success; 909706f2543Smrg} 910706f2543Smrg 911706f2543Smrgstatic int 912706f2543SmrgProcPanoramiXShmCreatePixmap(ClientPtr client) 913706f2543Smrg{ 914706f2543Smrg ScreenPtr pScreen = NULL; 915706f2543Smrg PixmapPtr pMap = NULL; 916706f2543Smrg DrawablePtr pDraw; 917706f2543Smrg DepthPtr pDepth; 918706f2543Smrg int i, j, result, rc; 919706f2543Smrg ShmDescPtr shmdesc; 920706f2543Smrg REQUEST(xShmCreatePixmapReq); 921706f2543Smrg unsigned int width, height, depth; 922706f2543Smrg unsigned long size; 923706f2543Smrg PanoramiXRes *newPix; 924706f2543Smrg 925706f2543Smrg REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 926706f2543Smrg client->errorValue = stuff->pid; 927706f2543Smrg if (!sharedPixmaps) 928706f2543Smrg return BadImplementation; 929706f2543Smrg LEGAL_NEW_RESOURCE(stuff->pid, client); 930706f2543Smrg rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, 931706f2543Smrg DixGetAttrAccess); 932706f2543Smrg if (rc != Success) 933706f2543Smrg return rc; 934706f2543Smrg 935706f2543Smrg VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 936706f2543Smrg 937706f2543Smrg width = stuff->width; 938706f2543Smrg height = stuff->height; 939706f2543Smrg depth = stuff->depth; 940706f2543Smrg if (!width || !height || !depth) 941706f2543Smrg { 942706f2543Smrg client->errorValue = 0; 943706f2543Smrg return BadValue; 944706f2543Smrg } 945706f2543Smrg if (width > 32767 || height > 32767) 946706f2543Smrg return BadAlloc; 947706f2543Smrg 948706f2543Smrg if (stuff->depth != 1) 949706f2543Smrg { 950706f2543Smrg pDepth = pDraw->pScreen->allowedDepths; 951706f2543Smrg for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++) 952706f2543Smrg if (pDepth->depth == stuff->depth) 953706f2543Smrg goto CreatePmap; 954706f2543Smrg client->errorValue = stuff->depth; 955706f2543Smrg return BadValue; 956706f2543Smrg } 957706f2543Smrg 958706f2543SmrgCreatePmap: 959706f2543Smrg size = PixmapBytePad(width, depth) * height; 960706f2543Smrg if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { 961706f2543Smrg if (size < width * height) 962706f2543Smrg return BadAlloc; 963706f2543Smrg } 964706f2543Smrg /* thankfully, offset is unsigned */ 965706f2543Smrg if (stuff->offset + size < size) 966706f2543Smrg return BadAlloc; 967706f2543Smrg 968706f2543Smrg VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); 969706f2543Smrg 970706f2543Smrg if(!(newPix = malloc(sizeof(PanoramiXRes)))) 971706f2543Smrg return BadAlloc; 972706f2543Smrg 973706f2543Smrg newPix->type = XRT_PIXMAP; 974706f2543Smrg newPix->u.pix.shared = TRUE; 975706f2543Smrg newPix->info[0].id = stuff->pid; 976706f2543Smrg for(j = 1; j < PanoramiXNumScreens; j++) 977706f2543Smrg newPix->info[j].id = FakeClientID(client->index); 978706f2543Smrg 979706f2543Smrg result = Success; 980706f2543Smrg 981706f2543Smrg FOR_NSCREENS(j) { 982706f2543Smrg ShmScrPrivateRec *screen_priv; 983706f2543Smrg pScreen = screenInfo.screens[j]; 984706f2543Smrg 985706f2543Smrg screen_priv = ShmGetScreenPriv(pScreen); 986706f2543Smrg pMap = (*screen_priv->shmFuncs->CreatePixmap)(pScreen, 987706f2543Smrg stuff->width, stuff->height, stuff->depth, 988706f2543Smrg shmdesc->addr + stuff->offset); 989706f2543Smrg 990706f2543Smrg if (pMap) { 991706f2543Smrg dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc); 992706f2543Smrg shmdesc->refcnt++; 993706f2543Smrg pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 994706f2543Smrg pMap->drawable.id = newPix->info[j].id; 995706f2543Smrg if (!AddResource(newPix->info[j].id, RT_PIXMAP, (pointer)pMap)) { 996706f2543Smrg result = BadAlloc; 997706f2543Smrg break; 998706f2543Smrg } 999706f2543Smrg } else { 1000706f2543Smrg result = BadAlloc; 1001706f2543Smrg break; 1002706f2543Smrg } 1003706f2543Smrg } 1004706f2543Smrg 1005706f2543Smrg if(result == BadAlloc) { 1006706f2543Smrg while(j--) 1007706f2543Smrg FreeResource(newPix->info[j].id, RT_NONE); 1008706f2543Smrg free(newPix); 1009706f2543Smrg } else 1010706f2543Smrg AddResource(stuff->pid, XRT_PIXMAP, newPix); 1011706f2543Smrg 1012706f2543Smrg return result; 1013706f2543Smrg} 1014706f2543Smrg#endif 1015706f2543Smrg 1016706f2543Smrgstatic PixmapPtr 1017706f2543SmrgfbShmCreatePixmap (ScreenPtr pScreen, 1018706f2543Smrg int width, int height, int depth, char *addr) 1019706f2543Smrg{ 1020706f2543Smrg PixmapPtr pPixmap; 1021706f2543Smrg 1022706f2543Smrg pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0); 1023706f2543Smrg if (!pPixmap) 1024706f2543Smrg return NullPixmap; 1025706f2543Smrg 1026706f2543Smrg if (!(*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth, 1027706f2543Smrg BitsPerPixel(depth), PixmapBytePad(width, depth), (pointer)addr)) { 1028706f2543Smrg (*pScreen->DestroyPixmap)(pPixmap); 1029706f2543Smrg return NullPixmap; 1030706f2543Smrg } 1031706f2543Smrg return pPixmap; 1032706f2543Smrg} 1033706f2543Smrg 1034706f2543Smrgstatic int 1035706f2543SmrgProcShmCreatePixmap(ClientPtr client) 1036706f2543Smrg{ 1037706f2543Smrg PixmapPtr pMap; 1038706f2543Smrg DrawablePtr pDraw; 1039706f2543Smrg DepthPtr pDepth; 1040706f2543Smrg int i, rc; 1041706f2543Smrg ShmDescPtr shmdesc; 1042706f2543Smrg ShmScrPrivateRec *screen_priv; 1043706f2543Smrg REQUEST(xShmCreatePixmapReq); 1044706f2543Smrg unsigned int width, height, depth; 1045706f2543Smrg unsigned long size; 1046706f2543Smrg 1047706f2543Smrg REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 1048706f2543Smrg client->errorValue = stuff->pid; 1049706f2543Smrg if (!sharedPixmaps) 1050706f2543Smrg return BadImplementation; 1051706f2543Smrg LEGAL_NEW_RESOURCE(stuff->pid, client); 1052706f2543Smrg rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, 1053706f2543Smrg DixGetAttrAccess); 1054706f2543Smrg if (rc != Success) 1055706f2543Smrg return rc; 1056706f2543Smrg 1057706f2543Smrg VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 1058706f2543Smrg 1059706f2543Smrg width = stuff->width; 1060706f2543Smrg height = stuff->height; 1061706f2543Smrg depth = stuff->depth; 1062706f2543Smrg if (!width || !height || !depth) 1063706f2543Smrg { 1064706f2543Smrg client->errorValue = 0; 1065706f2543Smrg return BadValue; 1066706f2543Smrg } 1067706f2543Smrg if (width > 32767 || height > 32767) 1068706f2543Smrg return BadAlloc; 1069706f2543Smrg 1070706f2543Smrg if (stuff->depth != 1) 1071706f2543Smrg { 1072706f2543Smrg pDepth = pDraw->pScreen->allowedDepths; 1073706f2543Smrg for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++) 1074706f2543Smrg if (pDepth->depth == stuff->depth) 1075706f2543Smrg goto CreatePmap; 1076706f2543Smrg client->errorValue = stuff->depth; 1077706f2543Smrg return BadValue; 1078706f2543Smrg } 1079706f2543Smrg 1080706f2543SmrgCreatePmap: 1081706f2543Smrg size = PixmapBytePad(width, depth) * height; 1082706f2543Smrg if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { 1083706f2543Smrg if (size < width * height) 1084706f2543Smrg return BadAlloc; 1085706f2543Smrg } 1086706f2543Smrg /* thankfully, offset is unsigned */ 1087706f2543Smrg if (stuff->offset + size < size) 1088706f2543Smrg return BadAlloc; 1089706f2543Smrg 1090706f2543Smrg VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); 1091706f2543Smrg screen_priv = ShmGetScreenPriv(pDraw->pScreen); 1092706f2543Smrg pMap = (*screen_priv->shmFuncs->CreatePixmap)( 1093706f2543Smrg pDraw->pScreen, stuff->width, 1094706f2543Smrg stuff->height, stuff->depth, 1095706f2543Smrg shmdesc->addr + stuff->offset); 1096706f2543Smrg if (pMap) 1097706f2543Smrg { 1098706f2543Smrg rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP, 1099706f2543Smrg pMap, RT_NONE, NULL, DixCreateAccess); 1100706f2543Smrg if (rc != Success) { 1101706f2543Smrg pDraw->pScreen->DestroyPixmap(pMap); 1102706f2543Smrg return rc; 1103706f2543Smrg } 1104706f2543Smrg dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc); 1105706f2543Smrg shmdesc->refcnt++; 1106706f2543Smrg pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 1107706f2543Smrg pMap->drawable.id = stuff->pid; 1108706f2543Smrg if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap)) 1109706f2543Smrg { 1110706f2543Smrg return Success; 1111706f2543Smrg } 1112706f2543Smrg } 1113706f2543Smrg return BadAlloc; 1114706f2543Smrg} 1115706f2543Smrg 1116706f2543Smrgstatic int 1117706f2543SmrgProcShmDispatch (ClientPtr client) 1118706f2543Smrg{ 1119706f2543Smrg REQUEST(xReq); 1120706f2543Smrg switch (stuff->data) 1121706f2543Smrg { 1122706f2543Smrg case X_ShmQueryVersion: 1123706f2543Smrg return ProcShmQueryVersion(client); 1124706f2543Smrg case X_ShmAttach: 1125706f2543Smrg return ProcShmAttach(client); 1126706f2543Smrg case X_ShmDetach: 1127706f2543Smrg return ProcShmDetach(client); 1128706f2543Smrg case X_ShmPutImage: 1129706f2543Smrg#ifdef PANORAMIX 1130706f2543Smrg if ( !noPanoramiXExtension ) 1131706f2543Smrg return ProcPanoramiXShmPutImage(client); 1132706f2543Smrg#endif 1133706f2543Smrg return ProcShmPutImage(client); 1134706f2543Smrg case X_ShmGetImage: 1135706f2543Smrg#ifdef PANORAMIX 1136706f2543Smrg if ( !noPanoramiXExtension ) 1137706f2543Smrg return ProcPanoramiXShmGetImage(client); 1138706f2543Smrg#endif 1139706f2543Smrg return ProcShmGetImage(client); 1140706f2543Smrg case X_ShmCreatePixmap: 1141706f2543Smrg#ifdef PANORAMIX 1142706f2543Smrg if ( !noPanoramiXExtension ) 1143706f2543Smrg return ProcPanoramiXShmCreatePixmap(client); 1144706f2543Smrg#endif 1145706f2543Smrg return ProcShmCreatePixmap(client); 1146706f2543Smrg default: 1147706f2543Smrg return BadRequest; 1148706f2543Smrg } 1149706f2543Smrg} 1150706f2543Smrg 1151706f2543Smrgstatic void 1152706f2543SmrgSShmCompletionEvent(xShmCompletionEvent *from, xShmCompletionEvent *to) 1153706f2543Smrg{ 1154706f2543Smrg to->type = from->type; 1155706f2543Smrg cpswaps(from->sequenceNumber, to->sequenceNumber); 1156706f2543Smrg cpswapl(from->drawable, to->drawable); 1157706f2543Smrg cpswaps(from->minorEvent, to->minorEvent); 1158706f2543Smrg to->majorEvent = from->majorEvent; 1159706f2543Smrg cpswapl(from->shmseg, to->shmseg); 1160706f2543Smrg cpswapl(from->offset, to->offset); 1161706f2543Smrg} 1162706f2543Smrg 1163706f2543Smrgstatic int 1164706f2543SmrgSProcShmQueryVersion(ClientPtr client) 1165706f2543Smrg{ 1166706f2543Smrg int n; 1167706f2543Smrg REQUEST(xShmQueryVersionReq); 1168706f2543Smrg 1169706f2543Smrg swaps(&stuff->length, n); 1170706f2543Smrg return ProcShmQueryVersion(client); 1171706f2543Smrg} 1172706f2543Smrg 1173706f2543Smrgstatic int 1174706f2543SmrgSProcShmAttach(ClientPtr client) 1175706f2543Smrg{ 1176706f2543Smrg int n; 1177706f2543Smrg REQUEST(xShmAttachReq); 1178706f2543Smrg swaps(&stuff->length, n); 1179706f2543Smrg REQUEST_SIZE_MATCH(xShmAttachReq); 1180706f2543Smrg swapl(&stuff->shmseg, n); 1181706f2543Smrg swapl(&stuff->shmid, n); 1182706f2543Smrg return ProcShmAttach(client); 1183706f2543Smrg} 1184706f2543Smrg 1185706f2543Smrgstatic int 1186706f2543SmrgSProcShmDetach(ClientPtr client) 1187706f2543Smrg{ 1188706f2543Smrg int n; 1189706f2543Smrg REQUEST(xShmDetachReq); 1190706f2543Smrg swaps(&stuff->length, n); 1191706f2543Smrg REQUEST_SIZE_MATCH(xShmDetachReq); 1192706f2543Smrg swapl(&stuff->shmseg, n); 1193706f2543Smrg return ProcShmDetach(client); 1194706f2543Smrg} 1195706f2543Smrg 1196706f2543Smrgstatic int 1197706f2543SmrgSProcShmPutImage(ClientPtr client) 1198706f2543Smrg{ 1199706f2543Smrg int n; 1200706f2543Smrg REQUEST(xShmPutImageReq); 1201706f2543Smrg swaps(&stuff->length, n); 1202706f2543Smrg REQUEST_SIZE_MATCH(xShmPutImageReq); 1203706f2543Smrg swapl(&stuff->drawable, n); 1204706f2543Smrg swapl(&stuff->gc, n); 1205706f2543Smrg swaps(&stuff->totalWidth, n); 1206706f2543Smrg swaps(&stuff->totalHeight, n); 1207706f2543Smrg swaps(&stuff->srcX, n); 1208706f2543Smrg swaps(&stuff->srcY, n); 1209706f2543Smrg swaps(&stuff->srcWidth, n); 1210706f2543Smrg swaps(&stuff->srcHeight, n); 1211706f2543Smrg swaps(&stuff->dstX, n); 1212706f2543Smrg swaps(&stuff->dstY, n); 1213706f2543Smrg swapl(&stuff->shmseg, n); 1214706f2543Smrg swapl(&stuff->offset, n); 1215706f2543Smrg return ProcShmPutImage(client); 1216706f2543Smrg} 1217706f2543Smrg 1218706f2543Smrgstatic int 1219706f2543SmrgSProcShmGetImage(ClientPtr client) 1220706f2543Smrg{ 1221706f2543Smrg int n; 1222706f2543Smrg REQUEST(xShmGetImageReq); 1223706f2543Smrg swaps(&stuff->length, n); 1224706f2543Smrg REQUEST_SIZE_MATCH(xShmGetImageReq); 1225706f2543Smrg swapl(&stuff->drawable, n); 1226706f2543Smrg swaps(&stuff->x, n); 1227706f2543Smrg swaps(&stuff->y, n); 1228706f2543Smrg swaps(&stuff->width, n); 1229706f2543Smrg swaps(&stuff->height, n); 1230706f2543Smrg swapl(&stuff->planeMask, n); 1231706f2543Smrg swapl(&stuff->shmseg, n); 1232706f2543Smrg swapl(&stuff->offset, n); 1233706f2543Smrg return ProcShmGetImage(client); 1234706f2543Smrg} 1235706f2543Smrg 1236706f2543Smrgstatic int 1237706f2543SmrgSProcShmCreatePixmap(ClientPtr client) 1238706f2543Smrg{ 1239706f2543Smrg int n; 1240706f2543Smrg REQUEST(xShmCreatePixmapReq); 1241706f2543Smrg swaps(&stuff->length, n); 1242706f2543Smrg REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 1243706f2543Smrg swapl(&stuff->pid, n); 1244706f2543Smrg swapl(&stuff->drawable, n); 1245706f2543Smrg swaps(&stuff->width, n); 1246706f2543Smrg swaps(&stuff->height, n); 1247706f2543Smrg swapl(&stuff->shmseg, n); 1248706f2543Smrg swapl(&stuff->offset, n); 1249706f2543Smrg return ProcShmCreatePixmap(client); 1250706f2543Smrg} 1251706f2543Smrg 1252706f2543Smrgstatic int 1253706f2543SmrgSProcShmDispatch (ClientPtr client) 1254706f2543Smrg{ 1255706f2543Smrg REQUEST(xReq); 1256706f2543Smrg switch (stuff->data) 1257706f2543Smrg { 1258706f2543Smrg case X_ShmQueryVersion: 1259706f2543Smrg return SProcShmQueryVersion(client); 1260706f2543Smrg case X_ShmAttach: 1261706f2543Smrg return SProcShmAttach(client); 1262706f2543Smrg case X_ShmDetach: 1263706f2543Smrg return SProcShmDetach(client); 1264706f2543Smrg case X_ShmPutImage: 1265706f2543Smrg return SProcShmPutImage(client); 1266706f2543Smrg case X_ShmGetImage: 1267706f2543Smrg return SProcShmGetImage(client); 1268706f2543Smrg case X_ShmCreatePixmap: 1269706f2543Smrg return SProcShmCreatePixmap(client); 1270706f2543Smrg default: 1271706f2543Smrg return BadRequest; 1272706f2543Smrg } 1273706f2543Smrg} 1274706f2543Smrg 1275706f2543Smrgvoid 1276706f2543SmrgShmExtensionInit(INITARGS) 1277706f2543Smrg{ 1278706f2543Smrg ExtensionEntry *extEntry; 1279706f2543Smrg int i; 1280706f2543Smrg 1281706f2543Smrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL 1282706f2543Smrg if (!CheckForShmSyscall()) 1283706f2543Smrg { 1284706f2543Smrg ErrorF("MIT-SHM extension disabled due to lack of kernel support\n"); 1285706f2543Smrg return; 1286706f2543Smrg } 1287706f2543Smrg#endif 1288706f2543Smrg 1289706f2543Smrg if (!ShmRegisterPrivates()) 1290706f2543Smrg return; 1291706f2543Smrg 1292706f2543Smrg sharedPixmaps = xFalse; 1293706f2543Smrg { 1294706f2543Smrg sharedPixmaps = xTrue; 1295706f2543Smrg for (i = 0; i < screenInfo.numScreens; i++) 1296706f2543Smrg { 1297706f2543Smrg ShmScrPrivateRec *screen_priv = ShmInitScreenPriv(screenInfo.screens[i]); 1298706f2543Smrg if (!screen_priv->shmFuncs) 1299706f2543Smrg screen_priv->shmFuncs = &miFuncs; 1300706f2543Smrg if (!screen_priv->shmFuncs->CreatePixmap) 1301706f2543Smrg sharedPixmaps = xFalse; 1302706f2543Smrg } 1303706f2543Smrg if (sharedPixmaps) 1304706f2543Smrg for (i = 0; i < screenInfo.numScreens; i++) 1305706f2543Smrg { 1306706f2543Smrg ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(screenInfo.screens[i]); 1307706f2543Smrg screen_priv->destroyPixmap = screenInfo.screens[i]->DestroyPixmap; 1308706f2543Smrg screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap; 1309706f2543Smrg } 1310706f2543Smrg } 1311706f2543Smrg ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg"); 1312706f2543Smrg if (ShmSegType && 1313706f2543Smrg (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors, 1314706f2543Smrg ProcShmDispatch, SProcShmDispatch, 1315706f2543Smrg ShmResetProc, StandardMinorOpcode))) 1316706f2543Smrg { 1317706f2543Smrg ShmReqCode = (unsigned char)extEntry->base; 1318706f2543Smrg ShmCompletionCode = extEntry->eventBase; 1319706f2543Smrg BadShmSegCode = extEntry->errorBase; 1320706f2543Smrg SetResourceTypeErrorValue(ShmSegType, BadShmSegCode); 1321706f2543Smrg EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent; 1322706f2543Smrg } 1323706f2543Smrg} 1324