|
|
1.1 ! root 1: /* ! 2: * File: shm1.c ! 3: * ! 4: * Purpose: System V Compatible Shared Memory Device Driver ! 5: * ! 6: * $Log: shm1.c,v $ ! 7: * Revision 2.3 93/08/09 13:46:24 bin ! 8: * Kernel 82 changes ! 9: * ! 10: * Revision 2.2 93/07/26 15:32:18 nigel ! 11: * Nigel's R80 ! 12: * ! 13: * Revision 1.3 93/04/14 10:23:10 root ! 14: * r75 ! 15: * ! 16: */ ! 17: ! 18: /* ! 19: * ---------------------------------------------------------------------- ! 20: * Includes. ! 21: */ ! 22: #include <sys/coherent.h> ! 23: #include <sys/types.h> ! 24: #include <sys/proc.h> ! 25: #include <sys/ipc.h> ! 26: #include <sys/shm.h> ! 27: #include <sys/errno.h> ! 28: ! 29: /* ! 30: * ---------------------------------------------------------------------- ! 31: * Definitions. ! 32: * Constants. ! 33: * Macros with argument lists. ! 34: * Typedefs. ! 35: * Enums. ! 36: */ ! 37: #define SHMBASE 0x80000000 /* Base shared memory address */ ! 38: /* These macros should be somewhere in the headers ???*/ ! 39: #define DATAST 0x400000 /* Start of the data virtual address */ ! 40: #define DATAEND 0x7FFFFF /* End of the data virtual address */ ! 41: #define STACKST 0x7C000000 /* Start of the stack */ ! 42: #define STACKEN 0x7FFFFFFF /* End of the stack virtual address */ ! 43: ! 44: /* ! 45: * ---------------------------------------------------------------------- ! 46: * Functions. ! 47: * Import Functions. ! 48: * Export Functions. ! 49: * Local Functions. ! 50: */ ! 51: extern SEG *shmAlloc(); /* shm0.c */ ! 52: char *ushmat(); ! 53: int ushmdt(); ! 54: int ushmctl(); ! 55: int ushmget(); ! 56: int iShmPerm(); /* Check permissions */ ! 57: caddr_t vCheckReqAdd(); /* Check attach address for shmat */ ! 58: /* ! 59: * ---------------------------------------------------------------------- ! 60: * Global Data. ! 61: * Import Variables. ! 62: * Export Variables. ! 63: * Local Variables. ! 64: */ ! 65: ! 66: /* Configurable variables - see /etc/conf/mtune. */ ! 67: extern int SHMMNI; ! 68: extern int SHMMAX; ! 69: ! 70: struct shmid_ds *shmids = NULL; /* Array of shared memory segments */ ! 71: SEG **shmsegs; /* Array of pointers to segments */ ! 72: /* ! 73: * ---------------------------------------------------------------------- ! 74: * Code. ! 75: */ ! 76: ! 77: /* ! 78: * Shmctl - Shared Memory Control Operations. ! 79: */ ! 80: int ! 81: ushmctl(iShmId, iCmd, pstShmId) ! 82: int iShmId, /* Shared memory id */ ! 83: iCmd; /* Command */ ! 84: struct shmid_ds *pstShmId; /* User shmid_ds buffer */ ! 85: { ! 86: register struct shmid_ds *rstIdp; ! 87: int iRet = 0; ! 88: ! 89: /* Check if id is in proper range. */ ! 90: if (iShmId >= SHMMNI || iShmId < 0) { ! 91: u.u_error = EINVAL; ! 92: return; ! 93: } ! 94: /* Check we did alloc. All allocatable arrays are alloced after ! 95: * the first ~correct usage of shmget. ! 96: */ ! 97: if (shmids == NULL) { ! 98: u.u_error = EINVAL; ! 99: return; ! 100: } ! 101: rstIdp = &shmids[iShmId]; /* Requested segment */ ! 102: ! 103: /* Check if segment is in used */ ! 104: if ((rstIdp->shm_perm.mode & IPC_ALLOC) == 0) { ! 105: u.u_error = EINVAL; ! 106: return; ! 107: } ! 108: ! 109: switch (iCmd) { ! 110: case IPC_STAT: ! 111: /* Check read permission for stat. */ ! 112: if (iShmPerm((rstIdp), SHM_R)) { ! 113: u.u_error = EACCES; ! 114: return; ! 115: } ! 116: /* Check if user gives a valid buffer */ ! 117: if (!useracc(pstShmId, sizeof(struct shmid_ds), 1)) { ! 118: u.u_error = EFAULT; ! 119: return; ! 120: } ! 121: /* kucopy will set u_error if error occurs */ ! 122: kucopy(rstIdp, pstShmId, sizeof(struct shmid_ds)); ! 123: break; ! 124: ! 125: case IPC_SET: ! 126: if ((u.u_uid != 0) && (u.u_uid != rstIdp->shm_perm.uid) && ! 127: (u.u_uid != rstIdp->shm_perm.cuid)) { ! 128: u.u_error = EPERM; ! 129: iRet = -1; ! 130: break; ! 131: } ! 132: rstIdp->shm_perm.uid = getuwd(&(pstShmId->shm_perm.uid)); ! 133: rstIdp->shm_perm.gid = getuwd(&(pstShmId->shm_perm.gid)); ! 134: rstIdp->shm_perm.mode &= ~0777; ! 135: rstIdp->shm_perm.mode |= getuwd(&(pstShmId->shm_perm.mode)) ! 136: & 0777; ! 137: break; ! 138: ! 139: case IPC_RMID: ! 140: if ((u.u_uid != 0) && (u.u_uid != rstIdp->shm_perm.uid) && ! 141: (u.u_uid != rstIdp->shm_perm.cuid)) { ! 142: u.u_error = EPERM; ! 143: iRet = -1; ! 144: break; ! 145: } ! 146: ! 147: /* SVR3 allows removing an attached segment. Even worse, the ! 148: * process that has the segment attached can keep using it. ! 149: * Some buggy third party software uses this "feature". ! 150: * So, we have to make it available too;-( ! 151: */ ! 152: rstIdp->shm_perm.seq = 0; ! 153: rstIdp->shm_perm.mode = 0; ! 154: ! 155: /* If segment is attached, set flag to be removed */ ! 156: if (rstIdp->shm_nattch > 0) ! 157: shmsegs[iShmId]->s_flags |= SRFBERM; ! 158: else /* remove it otherwise */ ! 159: shmFree(shmsegs[iShmId]); ! 160: shmsegs[iShmId] = NULL; ! 161: break; ! 162: ! 163: /* SHM_LOCK and SHM_UNLOCK: lock/unlock shared memory segement ! 164: * in core. Is not a part of iBCS2. ! 165: * Has no meaning for current 4.0.* release of COHERENT. ! 166: * Have been done for binary portability. ! 167: */ ! 168: case SHM_LOCK: ! 169: if (!u.u_uid) { ! 170: u.u_error = EPERM; ! 171: return; ! 172: } ! 173: break; ! 174: case SHM_UNLOCK: ! 175: if (!u.u_uid) { ! 176: u.u_error = EPERM; ! 177: return; ! 178: } ! 179: break; ! 180: ! 181: default: ! 182: u.u_error = EINVAL; ! 183: iRet = -1; ! 184: } ! 185: ! 186: return iRet; ! 187: } ! 188: ! 189: /* ! 190: * Shmget - Get Shared Memory Segment ! 191: * Return shared memory id if succed, -1 and set u_error otheriwse. ! 192: */ ! 193: int ! 194: ushmget(kShmKey, iShmSize, iShmFlg) ! 195: key_t kShmKey; /* Shared memory key */ ! 196: int iShmSize; /* Shared memory segment size */ ! 197: int iShmFlg; /* Flags */ ! 198: { ! 199: register struct shmid_ds *rstShmId; /* Work pointer */ ! 200: register struct shmid_ds *rstOldest = 0;/* Oldest free segment */ ! 201: register int i; /* Loop index */ ! 202: SEG *pstSeg; ! 203: ! 204: /* Check the requested segment size */ ! 205: if (iShmSize < 0 || iShmSize > SHMMAX) { ! 206: u.u_error = EINVAL; ! 207: return; ! 208: } ! 209: /* Init the shared memory on the first shmget. */ ! 210: if (shmids == NULL) ! 211: if (shminit()) { ! 212: u.u_error = ENOSPC; ! 213: return; ! 214: } ! 215: ! 216: /* Search for desire shared memory segment. */ ! 217: for (rstShmId = shmids, i = 0; i < SHMMNI; i++, rstShmId++) { ! 218: /* If segment is not alloced, we will look for the oldest ! 219: * free segment. We will use it to create a new one. ! 220: * The "oldest" will increase (a little) system reliability. ! 221: */ ! 222: if ((rstShmId->shm_perm.mode & IPC_ALLOC) == 0) { ! 223: if ((rstOldest == NULL) || ! 224: (rstOldest->shm_ctime > rstShmId->shm_ctime)) ! 225: rstOldest = rstShmId; ! 226: continue; ! 227: } ! 228: /* Do we need a new segment? */ ! 229: if (kShmKey == IPC_PRIVATE) ! 230: continue; ! 231: /* Keep going if key is different. The key is an element ! 232: * number of shmids ! 233: */ ! 234: if (kShmKey != rstShmId->shm_perm.key) ! 235: continue; ! 236: ! 237: /* We found the segment with requested key. */ ! 238: ! 239: /* Request was for the exclusive segment should fail. */ ! 240: if ((iShmFlg & IPC_CREAT) && (iShmFlg & IPC_EXCL)) { ! 241: u.u_error = EEXIST; ! 242: return; ! 243: } ! 244: ! 245: /* Check the requested size */ ! 246: if (rstShmId->shm_segsz < iShmSize) { ! 247: u.u_error = EINVAL; ! 248: return; ! 249: } ! 250: ! 251: /* Check permissions */ ! 252: if (iShmPerm(rstShmId, iShmFlg)) ! 253: return; ! 254: return i; ! 255: } ! 256: ! 257: /* We need to create a new segment */ ! 258: if (rstOldest == 0) { /* Check system limits */ ! 259: u.u_error = ENOSPC; ! 260: return; ! 261: } ! 262: if (!(iShmFlg & IPC_CREAT)) { ! 263: u.u_error = ENOENT; ! 264: return; ! 265: } ! 266: rstShmId = rstOldest; ! 267: /* Allocate a new shared memory segment */ ! 268: pstSeg = shmAlloc(iShmSize); ! 269: if (pstSeg == NULL) { ! 270: u.u_error = ENOSPC; ! 271: return; ! 272: } ! 273: /* Save it in shmsegs */ ! 274: shmsegs[rstShmId - shmids] = pstSeg; ! 275: ! 276: rstShmId->shm_perm.seq = (unsigned short) (rstShmId - shmids); ! 277: rstShmId->shm_segsz = iShmSize; ! 278: rstShmId->shm_atime = 0; ! 279: rstShmId->shm_dtime = 0; ! 280: rstShmId->shm_ctime = timer.t_time; ! 281: rstShmId->shm_cpid = SELF->p_pid; ! 282: rstShmId->shm_perm.cuid = rstShmId->shm_perm.uid = u.u_uid; ! 283: rstShmId->shm_perm.cgid = rstShmId->shm_perm.gid = u.u_gid; ! 284: rstShmId->shm_perm.mode = (iShmFlg & 0777) | IPC_ALLOC; ! 285: rstShmId->shm_perm.key = kShmKey; ! 286: ! 287: if (kShmKey == IPC_PRIVATE) ! 288: rstShmId->shm_perm.mode |= SHM_DEST; ! 289: ! 290: return rstShmId - shmids; ! 291: } ! 292: ! 293: /* ! 294: * Allocate space for shared memory data structures. ! 295: */ ! 296: int ! 297: shminit() ! 298: { ! 299: shmids = (struct shmid_ds *) kalloc(sizeof(struct shmid_ds) * SHMMNI); ! 300: if (shmids == NULL) ! 301: return -1; ! 302: ! 303: /* Allocate array of shared memory segments. We do not have to ! 304: * initalise it ! 305: */ ! 306: shmsegs = (SEG *) kalloc(sizeof(SEG *) * SHMMNI); ! 307: if (shmsegs == NULL) ! 308: return -1; ! 309: return 0; ! 310: } ! 311: ! 312: /* ! 313: * Attach shared memory segment. ! 314: */ ! 315: char * ! 316: ushmat(iSysId, pcShmAddr, iShmFlg) ! 317: int iSysId; /* System segment id */ ! 318: char *pcShmAddr; /* Address to attach */ ! 319: int iShmFlg; /* Flags */ ! 320: { ! 321: register PROC *rpstProc; /* Current process */ ! 322: register struct sr *rpstSr; /* Shared memory segments */ ! 323: struct sr *pstSrTmp; ! 324: SEG *pstSegSh; /* Segment to attach */ ! 325: struct shmid_ds *pstShmId; /* Pointer to a system segment*/ ! 326: unsigned int uSegId; /* Segment id */ ! 327: caddr_t vAttAddr; /* Address to attach */ ! 328: int i; /* Loop index */ ! 329: int iReadOnly = 0; /* 1 - read only, 0 - rw */ ! 330: ! 331: /* Check if iSysId is a valid shared memory id. */ ! 332: if (iSysId < 0 || iSysId > SHMMNI) { ! 333: u.u_error = EINVAL; ! 334: return; ! 335: } ! 336: /* Do we really have this segment? */ ! 337: pstShmId = shmids + iSysId; ! 338: if (pstShmId->shm_perm.seq != iSysId) { ! 339: u.u_error = EINVAL; ! 340: return; ! 341: } ! 342: /* Check permissions. */ ! 343: if (iShmFlg & SHM_RDONLY) ! 344: iReadOnly = 1; ! 345: if (iReadOnly) { ! 346: if (iShmPerm(pstShmId, 0444)) { ! 347: u.u_error = EACCES; ! 348: return; ! 349: } ! 350: } else { ! 351: if (iShmPerm(pstShmId, 0666)) { ! 352: u.u_error = EACCES; ! 353: return; ! 354: } ! 355: } ! 356: /* Check if process has free shm index. */ ! 357: rpstProc = SELF; ! 358: /* We will go through all NSHMSEG segments to see if any is free. */ ! 359: for (rpstSr = rpstProc->p_shmsr; rpstSr < rpstProc->p_shmsr + NSHMSEG; ! 360: rpstSr++) ! 361: if (rpstSr->sr_segp == NULL) ! 362: break; ! 363: /* The segment id is just an element number. */ ! 364: uSegId = rpstSr - rpstProc->p_shmsr; ! 365: /* If segment id is >= NSHMSEG we cannot attach any new segment. */ ! 366: if (uSegId >= NSHMSEG) { ! 367: u.u_error = EMFILE; ! 368: return; ! 369: } ! 370: /* Get the pointer to the shared memory segment */ ! 371: pstSegSh = shmsegs[iSysId]; ! 372: ! 373: /* Find an address to attach. ! 374: * There are two cases: process does not request the address, ! 375: * process requests the address. ! 376: * In the first case we have to take the first available free address. ! 377: * We will try to put a free page between the segments. ! 378: * In the second case we have to check if address is an available and ! 379: * attach to this address. ! 380: */ ! 381: /* First case. We have to find a free address. */ ! 382: if (pcShmAddr == NULL) { ! 383: /* Find a free space to attach. */ ! 384: for (pstSrTmp = rpstProc->p_shmsr, i = 0; i < NSHMSEG; ! 385: i++, pstSrTmp++) ! 386: if (pstSrTmp->sr_base == NULL) ! 387: break; ! 388: /* Check limit of attaches per process */ ! 389: if (i >= NSHMSEG) { ! 390: u.u_error = EINVAL; ! 391: return; ! 392: } ! 393: /* We will use the addresses starting from SHMBASE. ! 394: * Each new address can be SHMMAX + NBPC appart. ! 395: */ ! 396: vAttAddr = (caddr_t) (SHMBASE + i * (SHMMAX + NBPC)); ! 397: } else { ! 398: /* Requst attach to a specific address. This is none portable ! 399: * way to use a shared memory. ! 400: */ ! 401: if ((vAttAddr = vCheckReqAdd(pcShmAddr, iReadOnly)) < 0) { ! 402: printf("%s: attempt attach to 0x%x\n", ! 403: u.u_comm, pcShmAddr); ! 404: u.u_error = EINVAL; ! 405: return; ! 406: } ! 407: } ! 408: ! 409: if (!shmAtt(uSegId, vAttAddr, pstSegSh, iReadOnly)) { ! 410: u.u_error = EINVAL; ! 411: return; ! 412: } ! 413: pstShmId->shm_lpid = SELF->p_pid; ! 414: pstShmId->shm_atime = timer.t_time; ! 415: pstShmId->shm_dtime = 0; ! 416: pstShmId->shm_nattch = pstSegSh->s_urefc - 1; ! 417: /* Keep all attached addresses. We will need them for detach */ ! 418: return (char *) vAttAddr; ! 419: } ! 420: ! 421: /* ! 422: * Check requested address for attach. ! 423: * Just fail for the first release. ! 424: */ ! 425: caddr_t ! 426: vCheckReqAdd(pcAdd, iFlg) ! 427: char *pcAdd; /* Address to atatch */ ! 428: int iFlg; /* Mode flag */ ! 429: { ! 430: return (caddr_t) -1; ! 431: } ! 432: ! 433: /* ! 434: * Check permissions of the shared memory segment. ! 435: * Return 0 on success, -1 and set errno on error. ! 436: */ ! 437: int ! 438: iShmPerm(pstShmId, iShmFlg) ! 439: struct shmid_ds *pstShmId; ! 440: int iShmFlg; ! 441: { ! 442: int iShmMode; ! 443: ! 444: /* We need 9 lower order bits. There is a question what we have to do ! 445: * if someone sets an execute bits on. At this point we just ignore ! 446: * them. ! 447: */ ! 448: iShmMode = iShmFlg & 0666; ! 449: ! 450: /* For superuser or if mode is 0 */ ! 451: if (u.u_uid == 0 || !iShmMode) ! 452: return 0; ! 453: /* For owner or creator */ ! 454: if (u.u_uid == pstShmId->shm_perm.uid || u.u_uid ! 455: == pstShmId->shm_perm.cuid) { ! 456: if ((iShmMode & pstShmId->shm_perm.mode) & 0600) ! 457: return 0; ! 458: else { ! 459: u.u_error = EACCES; ! 460: return -1; ! 461: } ! 462: } ! 463: /* For group */ ! 464: if (u.u_gid == pstShmId->shm_perm.gid ! 465: || u.u_gid == pstShmId->shm_perm.cgid) { ! 466: if ((iShmMode & pstShmId->shm_perm.mode) & 060) ! 467: return 0; ! 468: else { ! 469: u.u_error = EACCES; ! 470: return -1; ! 471: } ! 472: } ! 473: /* For the rest of the world */ ! 474: if ((iShmMode & pstShmId->shm_perm.mode) & 06) ! 475: return 0; ! 476: else { ! 477: u.u_error = EACCES; ! 478: return -1; ! 479: } ! 480: /* We should never come here */ ! 481: u.u_error = EACCES; ! 482: return -1; ! 483: } ! 484: ! 485: /* ! 486: * ushmdt() - Detach shared memory segment. ! 487: * Find segment number and call shmDetach() (shm0.c). ! 488: */ ! 489: int ! 490: ushmdt(cpShmAddr) ! 491: char *cpShmAddr; /* Pointer to a segment */ ! 492: { ! 493: register PROC *rpstProc; /* Current process */ ! 494: register struct sr *rpstSr; /* Shared memory segments */ ! 495: int i; /* Loop indexe */ ! 496: ! 497: rpstProc = SELF; /* Get pointer to our process */ ! 498: ! 499: /* Go through all segments. */ ! 500: for (rpstSr = rpstProc->p_shmsr, i = 0; i < NSHMSEG; i++, rpstSr++) { ! 501: if (rpstSr->sr_base == (caddr_t) cpShmAddr) { ! 502: shmDetach(i); ! 503: return 0; ! 504: } ! 505: } ! 506: ! 507: /* We can come here only if we have invalid address */ ! 508: u.u_error = EINVAL; ! 509: return; ! 510: } ! 511: ! 512: /* ! 513: * shmSetDs(). Called from shm0.c. ! 514: * ! 515: * Given a pointer to shared memory segment, set shmid_ds. ! 516: */ ! 517: void ! 518: shmSetDs(rpstSeg) ! 519: register SEG *rpstSeg; ! 520: { ! 521: struct shmid_ds *pstShmId; /* Shared memory structure */ ! 522: int iShmId; /* Shared memory id */ ! 523: int j; /* Loop indexe */ ! 524: ! 525: for (j = 0; j < SHMMNI; j++) ! 526: if (shmsegs[j] == rpstSeg) ! 527: break; ! 528: ! 529: /* We should have this segment. */ ! 530: if (j >= SHMMNI) { ! 531: u.u_error = EINVAL; ! 532: return; ! 533: } ! 534: ! 535: iShmId = j; ! 536: pstShmId = shmids + iShmId; ! 537: ! 538: /* Set proper values */ ! 539: pstShmId->shm_lpid = SELF->p_pid; ! 540: pstShmId->shm_dtime = timer.t_time; ! 541: pstShmId->shm_nattch = rpstSeg->s_urefc - 1; ! 542: return; ! 543: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.