|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1990, 1996-1998 Apple Computer, Inc. ! 24: * All Rights Reserved. ! 25: */ ! 26: /* ! 27: * posix_shm.c : Support for POSIX shared memory apis ! 28: * ! 29: * File: posix_shm.c ! 30: * Author: Ananthakrishna Ramesh ! 31: * ! 32: * HISTORY ! 33: * 2-Sep-1999 A.Ramesh ! 34: * Created for MacOSX ! 35: * ! 36: */ ! 37: ! 38: #include <sys/cdefs.h> ! 39: #include <sys/param.h> ! 40: #include <sys/systm.h> ! 41: #include <sys/kernel.h> ! 42: #include <sys/file.h> ! 43: #include <sys/filedesc.h> ! 44: #include <sys/stat.h> ! 45: #include <sys/buf.h> ! 46: #include <sys/proc.h> ! 47: #include <sys/mount.h> ! 48: #include <sys/namei.h> ! 49: #include <sys/vnode.h> ! 50: #include <sys/ioctl.h> ! 51: #include <sys/tty.h> ! 52: #include <sys/malloc.h> ! 53: #include <sys/mman.h> ! 54: #include <sys/stat.h> ! 55: #include <mach/mach_types.h> ! 56: #include <mach/vm_prot.h> ! 57: #include <mach/vm_inherit.h> ! 58: #include <mach/kern_return.h> ! 59: #include <mach/memory_object_control.h> ! 60: ! 61: ! 62: #define PSHMNAMLEN 31 /* maximum name segment length we bother with */ ! 63: ! 64: struct pshminfo { ! 65: unsigned int pshm_flags; ! 66: unsigned int pshm_usecount; ! 67: off_t pshm_length; ! 68: mode_t pshm_mode; ! 69: uid_t pshm_uid; ! 70: gid_t pshm_gid; ! 71: char pshm_name[PSHMNAMLEN + 1]; /* segment name */ ! 72: void * pshm_memobject; ! 73: #if DIAGNOSTIC ! 74: unsigned int pshm_readcount; ! 75: unsigned int pshm_writecount; ! 76: struct proc * pshm_proc; ! 77: #endif /* DIAGNOSTIC */ ! 78: }; ! 79: #define PSHMINFO_NULL (struct pshminfo *)0 ! 80: ! 81: #define PSHM_NONE 1 ! 82: #define PSHM_DEFINED 2 ! 83: #define PSHM_ALLOCATED 4 ! 84: #define PSHM_MAPPED 8 ! 85: #define PSHM_INUSE 0x10 ! 86: #define PSHM_REMOVED 0x20 ! 87: #define PSHM_INCREATE 0x40 ! 88: #define PSHM_INDELETE 0x80 ! 89: ! 90: struct pshmcache { ! 91: LIST_ENTRY(pshmcache) pshm_hash; /* hash chain */ ! 92: struct pshminfo *pshminfo; /* vnode the name refers to */ ! 93: int pshm_nlen; /* length of name */ ! 94: char pshm_name[PSHMNAMLEN + 1]; /* segment name */ ! 95: }; ! 96: #define PSHMCACHE_NULL (struct pshmcache *)0 ! 97: ! 98: struct pshmstats { ! 99: long goodhits; /* hits that we can really use */ ! 100: long neghits; /* negative hits that we can use */ ! 101: long badhits; /* hits we must drop */ ! 102: long falsehits; /* hits with id mismatch */ ! 103: long miss; /* misses */ ! 104: long longnames; /* long names that ignore cache */ ! 105: }; ! 106: ! 107: struct pshmname { ! 108: char *pshm_nameptr; /* pointer to looked up name */ ! 109: long pshm_namelen; /* length of looked up component */ ! 110: u_long pshm_hash; /* hash value of looked up name */ ! 111: }; ! 112: ! 113: struct pshmnode { ! 114: off_t mapp_addr; ! 115: size_t map_size; ! 116: struct pshminfo *pinfo; ! 117: unsigned int pshm_usecount; ! 118: #if DIAGNOSTIC ! 119: unsigned int readcnt; ! 120: unsigned int writecnt; ! 121: #endif ! 122: }; ! 123: #define PSHMNODE_NULL (struct pshmnode *)0 ! 124: ! 125: ! 126: #define PSHMHASH(pnp) \ ! 127: (&pshmhashtbl[(pnp)->pshm_hash & pshmhash]) ! 128: LIST_HEAD(pshmhashhead, pshmcache) *pshmhashtbl; /* Hash Table */ ! 129: u_long pshmhash; /* size of hash table - 1 */ ! 130: long pshmnument; /* number of cache entries allocated */ ! 131: struct pshmstats pshmstats; /* cache effectiveness statistics */ ! 132: static pshm_init =0; ! 133: ! 134: int pshm_read __P((struct file *fp, struct uio *uio, ! 135: struct ucred *cred)); ! 136: int pshm_write __P((struct file *fp, struct uio *uio, ! 137: struct ucred *cred)); ! 138: int pshm_ioctl __P((struct file *fp, u_long com, ! 139: caddr_t data, struct proc *p)); ! 140: int pshm_select __P((struct file *fp, int which, ! 141: struct proc *p)); ! 142: int pshm_closefile __P((struct file *fp, struct proc *p)); ! 143: ! 144: struct fileops pshmops = ! 145: { pshm_read, pshm_write, pshm_ioctl, pshm_select, pshm_closefile }; ! 146: ! 147: ! 148: ! 149: /* ! 150: * Lookup an entry in the cache ! 151: * ! 152: * ! 153: * status of -1 is returned if matches ! 154: * If the lookup determines that the name does not exist ! 155: * (negative cacheing), a status of ENOENT is returned. If the lookup ! 156: * fails, a status of zero is returned. ! 157: */ ! 158: ! 159: int ! 160: pshm_cache_search(pshmp, pnp, pcache) ! 161: struct pshminfo **pshmp; ! 162: struct pshmname *pnp; ! 163: struct pshmcache **pcache; ! 164: { ! 165: register struct pshmcache *pcp, *nnp; ! 166: register struct pshmhashhead *pcpp; ! 167: ! 168: if (pnp->pshm_namelen > PSHMNAMLEN) { ! 169: pshmstats.longnames++; ! 170: return (0); ! 171: } ! 172: ! 173: pcpp = PSHMHASH(pnp); ! 174: for (pcp = pcpp->lh_first; pcp != 0; pcp = nnp) { ! 175: nnp = pcp->pshm_hash.le_next; ! 176: if (pcp->pshm_nlen == pnp->pshm_namelen && ! 177: !bcmp(pcp->pshm_name, pnp->pshm_nameptr, (u_int)pcp-> pshm_nlen)) ! 178: break; ! 179: } ! 180: ! 181: if (pcp == 0) { ! 182: pshmstats.miss++; ! 183: return (0); ! 184: } ! 185: ! 186: /* We found a "positive" match, return the vnode */ ! 187: if (pcp->pshminfo) { ! 188: pshmstats.goodhits++; ! 189: /* TOUCH(ncp); */ ! 190: *pshmp = pcp->pshminfo; ! 191: *pcache = pcp; ! 192: return (-1); ! 193: } ! 194: ! 195: /* ! 196: * We found a "negative" match, ENOENT notifies client of this match. ! 197: * The nc_vpid field records whether this is a whiteout. ! 198: */ ! 199: pshmstats.neghits++; ! 200: return (ENOENT); ! 201: } ! 202: ! 203: /* ! 204: * Add an entry to the cache. ! 205: */ ! 206: int ! 207: pshm_cache_add(pshmp, pnp) ! 208: struct pshminfo *pshmp; ! 209: struct pshmname *pnp; ! 210: { ! 211: register struct pshmcache *pcp; ! 212: register struct pshmhashhead *pcpp; ! 213: register struct pshminfo *dpinfo; ! 214: register struct pshmcache *dpcp; ! 215: ! 216: #if DIAGNOSTIC ! 217: if (pnp->pshm_namelen > NCHNAMLEN) ! 218: panic("cache_enter: name too long"); ! 219: #endif ! 220: ! 221: /* ! 222: * We allocate a new entry if we are less than the maximum ! 223: * allowed and the one at the front of the LRU list is in use. ! 224: * Otherwise we use the one at the front of the LRU list. ! 225: */ ! 226: pcp = (struct pshmcache *)_MALLOC(sizeof(struct pshmcache), M_SHM, M_WAITOK); ! 227: /* if the entry has already been added by some one else return */ ! 228: if (pshm_cache_search(&dpinfo, pnp, &dpcp) == -1) { ! 229: _FREE(pcp, M_SHM); ! 230: return(EEXIST); ! 231: } ! 232: pshmnument++; ! 233: ! 234: bzero(pcp, sizeof(struct pshmcache)); ! 235: /* ! 236: * Fill in cache info, if vp is NULL this is a "negative" cache entry. ! 237: * For negative entries, we have to record whether it is a whiteout. ! 238: * the whiteout flag is stored in the nc_vpid field which is ! 239: * otherwise unused. ! 240: */ ! 241: pcp->pshminfo = pshmp; ! 242: pcp->pshm_nlen = pnp->pshm_namelen; ! 243: bcopy(pnp->pshm_nameptr, pcp->pshm_name, (unsigned)pcp->pshm_nlen); ! 244: pcpp = PSHMHASH(pnp); ! 245: #if DIAGNOSTIC ! 246: { ! 247: register struct pshmcache *p; ! 248: ! 249: for (p = pcpp->lh_first; p != 0; p = p->pshm_hash.le_next) ! 250: if (p == pcp) ! 251: panic("cache_enter: duplicate"); ! 252: } ! 253: #endif ! 254: LIST_INSERT_HEAD(pcpp, pcp, pshm_hash); ! 255: return(0); ! 256: } ! 257: ! 258: /* ! 259: * Name cache initialization, from vfs_init() when we are booting ! 260: */ ! 261: void ! 262: pshm_cache_init() ! 263: { ! 264: pshmhashtbl = hashinit(desiredvnodes, M_SHM, &pshmhash); ! 265: pshm_init = 1; ! 266: } ! 267: ! 268: /* ! 269: * Invalidate a all entries to particular vnode. ! 270: * ! 271: * We actually just increment the v_id, that will do it. The entries will ! 272: * be purged by lookup as they get found. If the v_id wraps around, we ! 273: * need to ditch the entire cache, to avoid confusion. No valid vnode will ! 274: * ever have (v_id == 0). ! 275: */ ! 276: void ! 277: pshm_cache_purge(void) ! 278: { ! 279: struct pshmcache *pcp; ! 280: struct pshmhashhead *pcpp; ! 281: ! 282: for (pcpp = &pshmhashtbl[pshmhash]; pcpp >= pshmhashtbl; pcpp--) { ! 283: while (pcp = pcpp->lh_first) ! 284: pshm_cache_delete(pcp); ! 285: } ! 286: } ! 287: ! 288: pshm_cache_delete(pcp) ! 289: struct pshmcache *pcp; ! 290: { ! 291: #if DIAGNOSTIC ! 292: if (pcp->pshm_hash.le_prev == 0) ! 293: panic("namecache purge le_prev"); ! 294: if (pcp->pshm_hash.le_next == pcp) ! 295: panic("namecache purge le_next"); ! 296: #endif /* DIAGNOSTIC */ ! 297: LIST_REMOVE(pcp, pshm_hash); ! 298: pcp->pshm_hash.le_prev = 0; ! 299: pshmnument--; ! 300: } ! 301: ! 302: ! 303: struct shm_open_args { ! 304: const char *name; ! 305: int oflag; ! 306: int mode; ! 307: }; ! 308: ! 309: int ! 310: shm_open(p, uap, retval) ! 311: struct proc *p; ! 312: register struct shm_open_args *uap; ! 313: register_t *retval; ! 314: { ! 315: register struct filedesc *fdp = p->p_fd; ! 316: register struct file *fp; ! 317: register struct vnode *vp; ! 318: int flags, i; ! 319: struct file *nfp; ! 320: int type, indx, error; ! 321: struct pshmname nd; ! 322: struct pshminfo *pinfo; ! 323: extern struct fileops pshmops; ! 324: char * pnbuf; ! 325: char * nameptr; ! 326: char * cp; ! 327: size_t pathlen, plen; ! 328: int fmode ; ! 329: int cmode = uap->mode; ! 330: int incache = 0; ! 331: struct pshmnode * pnode = PSHMNODE_NULL; ! 332: struct pshmcache * pcache = PSHMCACHE_NULL; ! 333: ! 334: if(!pshm_init) ! 335: pshm_cache_init(); ! 336: ! 337: pinfo = PSHMINFO_NULL; ! 338: ! 339: MALLOC_ZONE(pnbuf, caddr_t, ! 340: MAXPATHLEN, M_NAMEI, M_WAITOK); ! 341: pathlen = MAXPATHLEN; ! 342: error = copyinstr(uap->name, pnbuf, ! 343: MAXPATHLEN, &pathlen); ! 344: if (error) { ! 345: goto bad; ! 346: } ! 347: if (pathlen > PSHMNAMLEN) { ! 348: error = ENAMETOOLONG; ! 349: goto bad; ! 350: } ! 351: ! 352: ! 353: #ifdef PSXSHM_NAME_RESTRICT ! 354: nameptr = pnbuf; ! 355: if (*nameptr == '/') { ! 356: while (*(nameptr++) == '/') { ! 357: plen--; ! 358: error = EINVAL; ! 359: goto bad; ! 360: } ! 361: } else { ! 362: error = EINVAL; ! 363: goto bad; ! 364: } ! 365: #endif /* PSXSHM_NAME_RESTRICT */ ! 366: ! 367: plen = pathlen; ! 368: nameptr = pnbuf; ! 369: nd.pshm_nameptr = nameptr; ! 370: nd.pshm_namelen = plen; ! 371: nd. pshm_hash =0; ! 372: ! 373: for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) { ! 374: nd.pshm_hash += (unsigned char)*cp * i; ! 375: } ! 376: ! 377: error = pshm_cache_search(&pinfo, &nd, &pcache); ! 378: ! 379: if (error == ENOENT) { ! 380: error = EINVAL; ! 381: goto bad; ! 382: ! 383: } ! 384: if (!error) { ! 385: incache = 0; ! 386: } else ! 387: incache = 1; ! 388: fmode = FFLAGS(uap->oflag); ! 389: if ((fmode & (FREAD | FWRITE))==0) ! 390: return(EINVAL); ! 391: ! 392: if (error = falloc(p, &nfp, &indx)) ! 393: return (error); ! 394: fp = nfp; ! 395: ! 396: cmode &= ALLPERMS; ! 397: ! 398: if (fmode & O_CREAT) { ! 399: /* shm obj exists and opened O_EXCL */ ! 400: if ((fmode & O_EXCL) && incache) { ! 401: #if notyet ! 402: if (pinfo->pshm_flags & PSHM_INDELETE) { ! 403: } ! 404: #endif ! 405: error = EEXIST; ! 406: goto bad; ! 407: } ! 408: pinfo = (struct pshminfo *)_MALLOC(sizeof(struct pshminfo), M_SHM, M_WAITOK); ! 409: bzero(pinfo, sizeof(struct pshminfo)); ! 410: pinfo->pshm_flags = PSHM_DEFINED | PSHM_INCREATE; ! 411: pinfo->pshm_usecount = 1; ! 412: pinfo->pshm_mode = cmode; ! 413: pinfo->pshm_uid = p->p_ucred->cr_uid; ! 414: pinfo->pshm_gid = p->p_ucred->cr_gid; ! 415: ! 416: } else { ! 417: /* O_CREAT is not set and the shm obecj does not exist */ ! 418: if (!incache) { ! 419: error = ENOENT; ! 420: goto bad; ! 421: } ! 422: if( pinfo->pshm_flags & PSHM_INDELETE) { ! 423: error = ENOENT; ! 424: goto bad; ! 425: } ! 426: if (error = pshm_access(pinfo, fmode, p->p_ucred, p)) ! 427: goto bad; ! 428: } ! 429: if (fmode & O_TRUNC) { ! 430: error = EINVAL; ! 431: goto bad1; ! 432: } ! 433: #if DIAGNOSTIC ! 434: if (fmode & FWRITE) ! 435: pinfo->pshm_writecount++; ! 436: if (fmode & FREAD) ! 437: pinfo->pshm_readcount++; ! 438: #endif ! 439: pnode = (struct pshmnode *)_MALLOC(sizeof(struct pshmnode), M_SHM, M_WAITOK); ! 440: bzero(pnode, sizeof(struct pshmnode)); ! 441: ! 442: if (!incache) { ! 443: if (error = pshm_cache_add(pinfo, &nd)) { ! 444: goto bad2; ! 445: } ! 446: } ! 447: pinfo->pshm_flags &= ~PSHM_INCREATE; ! 448: pinfo->pshm_usecount++; ! 449: pnode->pinfo = pinfo; ! 450: fp->f_flag = flags & FMASK; ! 451: fp->f_type = DTYPE_PSXSHM; ! 452: fp->f_ops = &pshmops; ! 453: fp->f_data = (caddr_t)pnode; ! 454: *fdflags(p, indx) &= ~UF_RESERVED; ! 455: *retval = indx; ! 456: return (0); ! 457: bad2: ! 458: _FREE(pnode, M_SHM); ! 459: ! 460: bad1: ! 461: _FREE(pinfo, M_SHM); ! 462: ! 463: bad: ! 464: _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); ! 465: return (error); ! 466: } ! 467: ! 468: ! 469: /* ARGSUSED */ ! 470: int ! 471: pshm_truncate(p, fp, fd, length, retval) ! 472: struct proc *p; ! 473: struct file *fp; ! 474: int fd; ! 475: off_t length; ! 476: register_t *retval; ! 477: { ! 478: struct pshminfo * pinfo; ! 479: struct pshmnode * pnode ; ! 480: kern_return_t kret; ! 481: vm_offset_t user_addr; ! 482: void * mem_object; ! 483: vm_size_t size; ! 484: ! 485: if (fp->f_type != DTYPE_PSXSHM) { ! 486: return(EINVAL); ! 487: } ! 488: ! 489: ! 490: if (((pnode = (struct pshmnode *)fp->f_data)) == PSHMNODE_NULL ) ! 491: return(EINVAL); ! 492: ! 493: if ((pinfo = pnode->pinfo) == PSHMINFO_NULL) ! 494: return(EINVAL); ! 495: if ((pinfo->pshm_flags & (PSHM_DEFINED | PSHM_ALLOCATED)) ! 496: != PSHM_DEFINED) { ! 497: return(EINVAL); ! 498: } ! 499: ! 500: size = round_page (length); ! 501: kret = vm_allocate(current_map(), &user_addr, size, TRUE); ! 502: if (kret != KERN_SUCCESS) ! 503: goto out; ! 504: ! 505: kret = mach_make_memory_entry (current_map(), &size, ! 506: user_addr, VM_PROT_DEFAULT, &mem_object, 0); ! 507: ! 508: if (kret != KERN_SUCCESS) ! 509: goto out; ! 510: ! 511: vm_deallocate(current_map(), user_addr, size); ! 512: ! 513: pinfo->pshm_flags &= ~PSHM_DEFINED; ! 514: pinfo->pshm_flags = PSHM_ALLOCATED; ! 515: pinfo->pshm_memobject = mem_object; ! 516: pinfo->pshm_length = size; ! 517: return(0); ! 518: ! 519: out: ! 520: switch (kret) { ! 521: case KERN_INVALID_ADDRESS: ! 522: case KERN_NO_SPACE: ! 523: return (ENOMEM); ! 524: case KERN_PROTECTION_FAILURE: ! 525: return (EACCES); ! 526: default: ! 527: return (EINVAL); ! 528: ! 529: } ! 530: } ! 531: ! 532: int ! 533: pshm_stat(pnode, sb) ! 534: struct pshmnode *pnode; ! 535: struct stat *sb; ! 536: { ! 537: struct pshminfo *pinfo; ! 538: ! 539: if ((pinfo = pnode->pinfo) == PSHMINFO_NULL) ! 540: return(EINVAL); ! 541: ! 542: bzero(sb, sizeof(struct stat)); ! 543: sb->st_mode = pinfo->pshm_mode; ! 544: sb->st_uid = pinfo->pshm_uid; ! 545: sb->st_gid = pinfo->pshm_gid; ! 546: sb->st_size = pinfo->pshm_length; ! 547: ! 548: return(0); ! 549: } ! 550: ! 551: int ! 552: pshm_access(struct pshminfo *pinfo, int mode, struct ucred *cred, struct proc *p) ! 553: { ! 554: mode_t mask; ! 555: register gid_t *gp; ! 556: int i, error; ! 557: ! 558: /* Otherwise, user id 0 always gets access. */ ! 559: if (cred->cr_uid == 0) ! 560: return (0); ! 561: ! 562: mask = 0; ! 563: ! 564: /* Otherwise, check the owner. */ ! 565: if (cred->cr_uid == pinfo->pshm_uid) { ! 566: if (mode & FREAD) ! 567: mask |= S_IRUSR; ! 568: if (mode & FWRITE) ! 569: mask |= S_IWUSR; ! 570: return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES); ! 571: } ! 572: ! 573: /* Otherwise, check the groups. */ ! 574: for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) ! 575: if (pinfo->pshm_gid == *gp) { ! 576: if (mode & FREAD) ! 577: mask |= S_IRGRP; ! 578: if (mode & FWRITE) ! 579: mask |= S_IWGRP; ! 580: return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES); ! 581: } ! 582: ! 583: /* Otherwise, check everyone else. */ ! 584: if (mode & FREAD) ! 585: mask |= S_IROTH; ! 586: if (mode & FWRITE) ! 587: mask |= S_IWOTH; ! 588: return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES); ! 589: } ! 590: struct mmap_args { ! 591: caddr_t addr; ! 592: size_t len; ! 593: int prot; ! 594: int flags; ! 595: int fd; ! 596: #ifdef DOUBLE_ALIGN_PARAMS ! 597: long pad; ! 598: #endif ! 599: off_t pos; ! 600: }; ! 601: ! 602: int ! 603: pshm_mmap(struct proc *p, struct mmap_args *uap, register_t *retval, struct file *fp, vm_size_t pageoff) ! 604: { ! 605: vm_offset_t user_addr = uap->addr; ! 606: vm_size_t user_size = uap->len ; ! 607: int prot = uap->prot; ! 608: int flags = uap->flags; ! 609: vm_offset_t file_pos = (vm_offset_t)uap->pos; ! 610: int fd = uap->fd; ! 611: vm_map_t user_map; ! 612: boolean_t find_space,docow; ! 613: kern_return_t kret; ! 614: struct pshminfo * pinfo; ! 615: struct pshmnode * pnode; ! 616: void * mem_object; ! 617: ! 618: if (user_size == 0) ! 619: return(0); ! 620: ! 621: if ((flags & MAP_SHARED) == 0) ! 622: return(EINVAL); ! 623: ! 624: ! 625: if ((prot & PROT_WRITE) && ((fp->f_flag & FWRITE) == 0)) { ! 626: return(EPERM); ! 627: } ! 628: ! 629: if (((pnode = (struct pshmnode *)fp->f_data)) == PSHMNODE_NULL ) ! 630: return(EINVAL); ! 631: ! 632: if ((pinfo = pnode->pinfo) == PSHMINFO_NULL) ! 633: return(EINVAL); ! 634: ! 635: if ((pinfo->pshm_flags & PSHM_ALLOCATED) != PSHM_ALLOCATED) { ! 636: return(EINVAL); ! 637: } ! 638: if (user_size > pinfo->pshm_length) { ! 639: return(EINVAL); ! 640: } ! 641: if (user_size + file_pos > pinfo->pshm_length) { ! 642: return(EINVAL); ! 643: } ! 644: if ((mem_object = pinfo->pshm_memobject) == NULL) { ! 645: return(EINVAL); ! 646: } ! 647: ! 648: ! 649: user_map = current_map(); ! 650: ! 651: if ((flags & MAP_FIXED) == 0) { ! 652: find_space = TRUE; ! 653: user_addr = round_page(user_addr); ! 654: } else { ! 655: if (user_addr != trunc_page(user_addr)) ! 656: return (EINVAL); ! 657: find_space = FALSE; ! 658: (void) vm_deallocate(user_map, user_addr, user_size); ! 659: } ! 660: kret = vm_allocate(user_map, &user_addr, user_size, find_space); ! 661: if (kret != KERN_SUCCESS) ! 662: goto out; ! 663: docow = FALSE; ! 664: ! 665: kret = vm_map(user_map, &user_addr, user_size, ! 666: 0, find_space, pinfo->pshm_memobject, file_pos, docow, ! 667: prot, VM_PROT_DEFAULT, ! 668: VM_INHERIT_DEFAULT); ! 669: ! 670: if (kret != KERN_SUCCESS) ! 671: goto out; ! 672: kret = vm_inherit(user_map, user_addr, user_size, ! 673: VM_INHERIT_SHARE); ! 674: if (kret != KERN_SUCCESS) { ! 675: (void) vm_deallocate(user_map, user_addr, user_size); ! 676: goto out; ! 677: } ! 678: pnode->mapp_addr = user_addr; ! 679: pnode->map_size = user_size; ! 680: pinfo->pshm_flags |= (PSHM_MAPPED | PSHM_INUSE); ! 681: out: ! 682: switch (kret) { ! 683: case KERN_SUCCESS: ! 684: *fdflags(p, fd) |= UF_MAPPED; ! 685: *retval = (register_t)(user_addr + pageoff); ! 686: return (0); ! 687: case KERN_INVALID_ADDRESS: ! 688: case KERN_NO_SPACE: ! 689: return (ENOMEM); ! 690: case KERN_PROTECTION_FAILURE: ! 691: return (EACCES); ! 692: default: ! 693: return (EINVAL); ! 694: } ! 695: ! 696: } ! 697: ! 698: struct shm_unlink_args { ! 699: const char *name; ! 700: }; ! 701: ! 702: int ! 703: shm_unlink(p, uap, retval) ! 704: struct proc *p; ! 705: register struct shm_unlink_args *uap; ! 706: register_t *retval; ! 707: { ! 708: register struct filedesc *fdp = p->p_fd; ! 709: register struct file *fp; ! 710: int flags, i; ! 711: int error=0; ! 712: struct pshmname nd; ! 713: struct pshminfo *pinfo; ! 714: extern struct fileops pshmops; ! 715: char * pnbuf; ! 716: char * nameptr; ! 717: char * cp; ! 718: size_t pathlen, plen; ! 719: int fmode, cmode ; ! 720: int incache = 0; ! 721: struct pshmnode * pnode = PSHMNODE_NULL; ! 722: struct pshmcache *pcache = PSHMCACHE_NULL; ! 723: kern_return_t kret; ! 724: ! 725: pinfo = PSHMINFO_NULL; ! 726: ! 727: MALLOC_ZONE(pnbuf, caddr_t, ! 728: MAXPATHLEN, M_NAMEI, M_WAITOK); ! 729: pathlen = MAXPATHLEN; ! 730: error = copyinstr(uap->name, pnbuf, ! 731: MAXPATHLEN, &pathlen); ! 732: if (error) { ! 733: goto bad; ! 734: } ! 735: if (pathlen > PSHMNAMLEN) { ! 736: error = ENAMETOOLONG; ! 737: goto bad; ! 738: } ! 739: ! 740: ! 741: #ifdef PSXSHM_NAME_RESTRICT ! 742: nameptr = pnbuf; ! 743: if (*nameptr == '/') { ! 744: while (*(nameptr++) == '/') { ! 745: plen--; ! 746: error = EINVAL; ! 747: goto bad; ! 748: } ! 749: } else { ! 750: error = EINVAL; ! 751: goto bad; ! 752: } ! 753: #endif /* PSXSHM_NAME_RESTRICT */ ! 754: ! 755: plen = pathlen; ! 756: nameptr = pnbuf; ! 757: nd.pshm_nameptr = nameptr; ! 758: nd.pshm_namelen = plen; ! 759: nd. pshm_hash =0; ! 760: ! 761: for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) { ! 762: nd.pshm_hash += (unsigned char)*cp * i; ! 763: } ! 764: ! 765: error = pshm_cache_search(&pinfo, &nd, &pcache); ! 766: ! 767: if (error == ENOENT) { ! 768: error = EINVAL; ! 769: goto bad; ! 770: ! 771: } ! 772: if (!error) { ! 773: error = EINVAL; ! 774: goto bad; ! 775: } else ! 776: incache = 1; ! 777: ! 778: if ((pinfo->pshm_flags & (PSHM_DEFINED | PSHM_ALLOCATED))==0) { ! 779: return (EINVAL); ! 780: } ! 781: ! 782: if (pinfo->pshm_flags & PSHM_INDELETE) { ! 783: error = 0; ! 784: goto bad; ! 785: } ! 786: pinfo->pshm_flags |= PSHM_INDELETE; ! 787: pinfo->pshm_usecount--; ! 788: kret = mach_destroy_memory_entry(pinfo->pshm_memobject); ! 789: pshm_cache_delete(pcache); ! 790: _FREE(pcache, M_SHM); ! 791: pinfo->pshm_flags |= PSHM_REMOVED; ! 792: error = 0; ! 793: bad: ! 794: _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); ! 795: return (error); ! 796: out: ! 797: switch (kret) { ! 798: case KERN_INVALID_ADDRESS: ! 799: case KERN_PROTECTION_FAILURE: ! 800: return (EACCES); ! 801: default: ! 802: return (EINVAL); ! 803: } ! 804: } ! 805: int ! 806: pshm_closefile(fp, p) ! 807: struct file *fp; ! 808: struct proc *p; ! 809: { ! 810: ! 811: return (pshm_close(((struct pshmnode *)fp->f_data), fp->f_flag, ! 812: fp->f_cred, p)); ! 813: } ! 814: ! 815: int ! 816: pshm_close(pnode, flags, cred, p) ! 817: register struct pshmnode *pnode; ! 818: int flags; ! 819: struct ucred *cred; ! 820: struct proc *p; ! 821: { ! 822: int error=0; ! 823: kern_return_t kret; ! 824: register struct pshminfo *pinfo; ! 825: ! 826: if ((pinfo = pnode->pinfo) == PSHMINFO_NULL) ! 827: return(EINVAL); ! 828: ! 829: if ((pinfo->pshm_flags & PSHM_ALLOCATED) != PSHM_ALLOCATED) { ! 830: return(EINVAL); ! 831: } ! 832: #if DIAGNOSTIC ! 833: if(!pinfo->pshm_usecount) { ! 834: kprintf("negative usecount in pshm_close\n"); ! 835: } ! 836: #endif /* DIAGNOSTIC */ ! 837: pinfo->pshm_usecount--; ! 838: ! 839: if ((pinfo->pshm_flags & PSHM_REMOVED) && !pinfo->pshm_usecount) { ! 840: _FREE(pinfo,M_SHM); ! 841: } ! 842: _FREE(pnode, M_SHM); ! 843: return (error); ! 844: } ! 845: int ! 846: pshm_read(struct file *fp, struct uio *uio, struct ucred *cred) ! 847: { ! 848: return(EOPNOTSUPP); ! 849: } ! 850: int ! 851: pshm_write(struct file *fp, struct uio *uio, struct ucred *cred) ! 852: { ! 853: return(EOPNOTSUPP); ! 854: } ! 855: int ! 856: pshm_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p) ! 857: { ! 858: return(EOPNOTSUPP); ! 859: } ! 860: int ! 861: pshm_select(struct file *fp, int which, struct proc *p) ! 862: { ! 863: return(EOPNOTSUPP); ! 864: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.