|
|
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: * Implementation of SVID messages ! 24: * ! 25: * Author: Daniel Boulet ! 26: * ! 27: * Copyright 1993 Daniel Boulet and RTMX Inc. ! 28: * ! 29: * This system call was implemented by Daniel Boulet under contract from RTMX. ! 30: * ! 31: * Redistribution and use in source forms, with and without modification, ! 32: * are permitted provided that this entire comment appears intact. ! 33: * ! 34: * Redistribution in binary form may occur without any restrictions. ! 35: * Obviously, it would be nice if you gave credit where credit is due ! 36: * but requiring it would be too onerous. ! 37: * ! 38: * This software is provided ``AS IS'' without any warranties of any kind. ! 39: */ ! 40: ! 41: #include <sys/param.h> ! 42: #include <sys/systm.h> ! 43: #include <sys/sysproto.h> ! 44: #include <sys/kernel.h> ! 45: #include <sys/proc.h> ! 46: #include <sys/msg.h> ! 47: #include <sys/sysent.h> ! 48: ! 49: static void msginit __P((void *)); ! 50: SYSINIT(sysv_msg, SI_SUB_SYSV_MSG, SI_ORDER_FIRST, msginit, NULL) ! 51: ! 52: #define MSG_DEBUG ! 53: #undef MSG_DEBUG_OK ! 54: ! 55: #ifndef _SYS_SYSPROTO_H_ ! 56: struct msgctl_args; ! 57: int msgctl __P((struct proc *p, struct msgctl_args *uap)); ! 58: struct msgget_args; ! 59: int msgget __P((struct proc *p, struct msgget_args *uap)); ! 60: struct msgsnd_args; ! 61: int msgsnd __P((struct proc *p, struct msgsnd_args *uap)); ! 62: struct msgrcv_args; ! 63: int msgrcv __P((struct proc *p, struct msgrcv_args *uap)); ! 64: #endif ! 65: static void msg_freehdr __P((struct msg *msghdr)); ! 66: ! 67: /* XXX casting to (sy_call_t *) is bogus, as usual. */ ! 68: static sy_call_t *msgcalls[] = { ! 69: (sy_call_t *)msgctl, (sy_call_t *)msgget, ! 70: (sy_call_t *)msgsnd, (sy_call_t *)msgrcv ! 71: }; ! 72: ! 73: static int nfree_msgmaps; /* # of free map entries */ ! 74: static short free_msgmaps; /* head of linked list of free map entries */ ! 75: static struct msg *free_msghdrs; /* list of free msg headers */ ! 76: char *msgpool; /* MSGMAX byte long msg buffer pool */ ! 77: struct msgmap *msgmaps; /* MSGSEG msgmap structures */ ! 78: struct msg *msghdrs; /* MSGTQL msg headers */ ! 79: struct msqid_ds *msqids; /* MSGMNI msqid_ds struct's */ ! 80: ! 81: void ! 82: msginit(dummy) ! 83: void *dummy; ! 84: { ! 85: register int i; ! 86: ! 87: /* ! 88: * msginfo.msgssz should be a power of two for efficiency reasons. ! 89: * It is also pretty silly if msginfo.msgssz is less than 8 ! 90: * or greater than about 256 so ... ! 91: */ ! 92: ! 93: i = 8; ! 94: while (i < 1024 && i != msginfo.msgssz) ! 95: i <<= 1; ! 96: if (i != msginfo.msgssz) { ! 97: printf("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz, ! 98: msginfo.msgssz); ! 99: panic("msginfo.msgssz not a small power of 2"); ! 100: } ! 101: ! 102: if (msginfo.msgseg > 32767) { ! 103: printf("msginfo.msgseg=%d\n", msginfo.msgseg); ! 104: panic("msginfo.msgseg > 32767"); ! 105: } ! 106: ! 107: if (msgmaps == NULL) ! 108: panic("msgmaps is NULL"); ! 109: ! 110: for (i = 0; i < msginfo.msgseg; i++) { ! 111: if (i > 0) ! 112: msgmaps[i-1].next = i; ! 113: msgmaps[i].next = -1; /* implies entry is available */ ! 114: } ! 115: free_msgmaps = 0; ! 116: nfree_msgmaps = msginfo.msgseg; ! 117: ! 118: if (msghdrs == NULL) ! 119: panic("msghdrs is NULL"); ! 120: ! 121: for (i = 0; i < msginfo.msgtql; i++) { ! 122: msghdrs[i].msg_type = 0; ! 123: if (i > 0) ! 124: msghdrs[i-1].msg_next = &msghdrs[i]; ! 125: msghdrs[i].msg_next = NULL; ! 126: } ! 127: free_msghdrs = &msghdrs[0]; ! 128: ! 129: if (msqids == NULL) ! 130: panic("msqids is NULL"); ! 131: ! 132: for (i = 0; i < msginfo.msgmni; i++) { ! 133: msqids[i].msg_qbytes = 0; /* implies entry is available */ ! 134: msqids[i].msg_perm.seq = 0; /* reset to a known value */ ! 135: } ! 136: } ! 137: ! 138: /* ! 139: * Entry point for all MSG calls ! 140: */ ! 141: int ! 142: msgsys(p, uap) ! 143: struct proc *p; ! 144: /* XXX actually varargs. */ ! 145: struct msgsys_args /* { ! 146: u_int which; ! 147: int a2; ! 148: int a3; ! 149: int a4; ! 150: int a5; ! 151: int a6; ! 152: } */ *uap; ! 153: { ! 154: ! 155: if (uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0])) ! 156: return (EINVAL); ! 157: return ((*msgcalls[uap->which])(p, &uap->a2)); ! 158: } ! 159: ! 160: static void ! 161: msg_freehdr(msghdr) ! 162: struct msg *msghdr; ! 163: { ! 164: while (msghdr->msg_ts > 0) { ! 165: short next; ! 166: if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg) ! 167: panic("msghdr->msg_spot out of range"); ! 168: next = msgmaps[msghdr->msg_spot].next; ! 169: msgmaps[msghdr->msg_spot].next = free_msgmaps; ! 170: free_msgmaps = msghdr->msg_spot; ! 171: nfree_msgmaps++; ! 172: msghdr->msg_spot = next; ! 173: if (msghdr->msg_ts >= msginfo.msgssz) ! 174: msghdr->msg_ts -= msginfo.msgssz; ! 175: else ! 176: msghdr->msg_ts = 0; ! 177: } ! 178: if (msghdr->msg_spot != -1) ! 179: panic("msghdr->msg_spot != -1"); ! 180: msghdr->msg_next = free_msghdrs; ! 181: free_msghdrs = msghdr; ! 182: } ! 183: ! 184: #ifndef _SYS_SYSPROTO_H_ ! 185: struct msgctl_args { ! 186: int msqid; ! 187: int cmd; ! 188: struct msqid_ds *buf; ! 189: }; ! 190: #endif ! 191: ! 192: int ! 193: msgctl(p, uap) ! 194: struct proc *p; ! 195: register struct msgctl_args *uap; ! 196: { ! 197: int msqid = uap->msqid; ! 198: int cmd = uap->cmd; ! 199: struct msqid_ds *user_msqptr = uap->buf; ! 200: struct ucred *cred = p->p_ucred; ! 201: int rval, eval; ! 202: struct msqid_ds msqbuf; ! 203: register struct msqid_ds *msqptr; ! 204: ! 205: #ifdef MSG_DEBUG_OK ! 206: printf("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr); ! 207: #endif ! 208: ! 209: msqid = IPCID_TO_IX(msqid); ! 210: ! 211: if (msqid < 0 || msqid >= msginfo.msgmni) { ! 212: #ifdef MSG_DEBUG_OK ! 213: printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid, ! 214: msginfo.msgmni); ! 215: #endif ! 216: return(EINVAL); ! 217: } ! 218: ! 219: msqptr = &msqids[msqid]; ! 220: ! 221: if (msqptr->msg_qbytes == 0) { ! 222: #ifdef MSG_DEBUG_OK ! 223: printf("no such msqid\n"); ! 224: #endif ! 225: return(EINVAL); ! 226: } ! 227: if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) { ! 228: #ifdef MSG_DEBUG_OK ! 229: printf("wrong sequence number\n"); ! 230: #endif ! 231: return(EINVAL); ! 232: } ! 233: ! 234: eval = 0; ! 235: rval = 0; ! 236: ! 237: switch (cmd) { ! 238: ! 239: case IPC_RMID: ! 240: { ! 241: struct msg *msghdr; ! 242: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_M))) ! 243: return(eval); ! 244: /* Free the message headers */ ! 245: msghdr = msqptr->msg_first; ! 246: while (msghdr != NULL) { ! 247: struct msg *msghdr_tmp; ! 248: ! 249: /* Free the segments of each message */ ! 250: msqptr->msg_cbytes -= msghdr->msg_ts; ! 251: msqptr->msg_qnum--; ! 252: msghdr_tmp = msghdr; ! 253: msghdr = msghdr->msg_next; ! 254: msg_freehdr(msghdr_tmp); ! 255: } ! 256: ! 257: if (msqptr->msg_cbytes != 0) ! 258: panic("msg_cbytes is messed up"); ! 259: if (msqptr->msg_qnum != 0) ! 260: panic("msg_qnum is messed up"); ! 261: ! 262: msqptr->msg_qbytes = 0; /* Mark it as free */ ! 263: ! 264: wakeup((caddr_t)msqptr); ! 265: } ! 266: ! 267: break; ! 268: ! 269: case IPC_SET: ! 270: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_M))) ! 271: return(eval); ! 272: if ((eval = copyin(user_msqptr, &msqbuf, sizeof(msqbuf))) != 0) ! 273: return(eval); ! 274: if (msqbuf.msg_qbytes > msqptr->msg_qbytes) { ! 275: eval = suser(cred, &p->p_acflag); ! 276: if (eval) ! 277: return(eval); ! 278: } ! 279: if (msqbuf.msg_qbytes > msginfo.msgmnb) { ! 280: #ifdef MSG_DEBUG_OK ! 281: printf("can't increase msg_qbytes beyond %d (truncating)\n", ! 282: msginfo.msgmnb); ! 283: #endif ! 284: msqbuf.msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */ ! 285: } ! 286: if (msqbuf.msg_qbytes == 0) { ! 287: #ifdef MSG_DEBUG_OK ! 288: printf("can't reduce msg_qbytes to 0\n"); ! 289: #endif ! 290: return(EINVAL); /* non-standard errno! */ ! 291: } ! 292: msqptr->msg_perm.uid = msqbuf.msg_perm.uid; /* change the owner */ ! 293: msqptr->msg_perm.gid = msqbuf.msg_perm.gid; /* change the owner */ ! 294: msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) | ! 295: (msqbuf.msg_perm.mode & 0777); ! 296: msqptr->msg_qbytes = msqbuf.msg_qbytes; ! 297: msqptr->msg_ctime = time_second; ! 298: break; ! 299: ! 300: case IPC_STAT: ! 301: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) { ! 302: #ifdef MSG_DEBUG_OK ! 303: printf("requester doesn't have read access\n"); ! 304: #endif ! 305: return(eval); ! 306: } ! 307: eval = copyout((caddr_t)msqptr, user_msqptr, ! 308: sizeof(struct msqid_ds)); ! 309: break; ! 310: ! 311: default: ! 312: #ifdef MSG_DEBUG_OK ! 313: printf("invalid command %d\n", cmd); ! 314: #endif ! 315: return(EINVAL); ! 316: } ! 317: ! 318: if (eval == 0) ! 319: p->p_retval[0] = rval; ! 320: return(eval); ! 321: } ! 322: ! 323: #ifndef _SYS_SYSPROTO_H_ ! 324: struct msgget_args { ! 325: key_t key; ! 326: int msgflg; ! 327: }; ! 328: #endif ! 329: ! 330: int ! 331: msgget(p, uap) ! 332: struct proc *p; ! 333: register struct msgget_args *uap; ! 334: { ! 335: int msqid, eval; ! 336: int key = uap->key; ! 337: int msgflg = uap->msgflg; ! 338: struct ucred *cred = p->p_ucred; ! 339: register struct msqid_ds *msqptr = NULL; ! 340: ! 341: #ifdef MSG_DEBUG_OK ! 342: printf("msgget(0x%x, 0%o)\n", key, msgflg); ! 343: #endif ! 344: ! 345: if (key != IPC_PRIVATE) { ! 346: for (msqid = 0; msqid < msginfo.msgmni; msqid++) { ! 347: msqptr = &msqids[msqid]; ! 348: if (msqptr->msg_qbytes != 0 && ! 349: msqptr->msg_perm.key == key) ! 350: break; ! 351: } ! 352: if (msqid < msginfo.msgmni) { ! 353: #ifdef MSG_DEBUG_OK ! 354: printf("found public key\n"); ! 355: #endif ! 356: if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) { ! 357: #ifdef MSG_DEBUG_OK ! 358: printf("not exclusive\n"); ! 359: #endif ! 360: return(EEXIST); ! 361: } ! 362: if ((eval = ipcperm(cred, &msqptr->msg_perm, msgflg & 0700 ))) { ! 363: #ifdef MSG_DEBUG_OK ! 364: printf("requester doesn't have 0%o access\n", ! 365: msgflg & 0700); ! 366: #endif ! 367: return(eval); ! 368: } ! 369: goto found; ! 370: } ! 371: } ! 372: ! 373: #ifdef MSG_DEBUG_OK ! 374: printf("need to allocate the msqid_ds\n"); ! 375: #endif ! 376: if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) { ! 377: for (msqid = 0; msqid < msginfo.msgmni; msqid++) { ! 378: /* ! 379: * Look for an unallocated and unlocked msqid_ds. ! 380: * msqid_ds's can be locked by msgsnd or msgrcv while ! 381: * they are copying the message in/out. We can't ! 382: * re-use the entry until they release it. ! 383: */ ! 384: msqptr = &msqids[msqid]; ! 385: if (msqptr->msg_qbytes == 0 && ! 386: (msqptr->msg_perm.mode & MSG_LOCKED) == 0) ! 387: break; ! 388: } ! 389: if (msqid == msginfo.msgmni) { ! 390: #ifdef MSG_DEBUG_OK ! 391: printf("no more msqid_ds's available\n"); ! 392: #endif ! 393: return(ENOSPC); ! 394: } ! 395: #ifdef MSG_DEBUG_OK ! 396: printf("msqid %d is available\n", msqid); ! 397: #endif ! 398: msqptr->msg_perm.key = key; ! 399: msqptr->msg_perm.cuid = cred->cr_uid; ! 400: msqptr->msg_perm.uid = cred->cr_uid; ! 401: msqptr->msg_perm.cgid = cred->cr_gid; ! 402: msqptr->msg_perm.gid = cred->cr_gid; ! 403: msqptr->msg_perm.mode = (msgflg & 0777); ! 404: /* Make sure that the returned msqid is unique */ ! 405: msqptr->msg_perm.seq++; ! 406: msqptr->msg_first = NULL; ! 407: msqptr->msg_last = NULL; ! 408: msqptr->msg_cbytes = 0; ! 409: msqptr->msg_qnum = 0; ! 410: msqptr->msg_qbytes = msginfo.msgmnb; ! 411: msqptr->msg_lspid = 0; ! 412: msqptr->msg_lrpid = 0; ! 413: msqptr->msg_stime = 0; ! 414: msqptr->msg_rtime = 0; ! 415: msqptr->msg_ctime = time_second; ! 416: } else { ! 417: #ifdef MSG_DEBUG_OK ! 418: printf("didn't find it and wasn't asked to create it\n"); ! 419: #endif ! 420: return(ENOENT); ! 421: } ! 422: ! 423: found: ! 424: /* Construct the unique msqid */ ! 425: p->p_retval[0] = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm); ! 426: return(0); ! 427: } ! 428: ! 429: #ifndef _SYS_SYSPROTO_H_ ! 430: struct msgsnd_args { ! 431: int msqid; ! 432: void *msgp; ! 433: size_t msgsz; ! 434: int msgflg; ! 435: }; ! 436: #endif ! 437: ! 438: int ! 439: msgsnd(p, uap) ! 440: struct proc *p; ! 441: register struct msgsnd_args *uap; ! 442: { ! 443: int msqid = uap->msqid; ! 444: void *user_msgp = uap->msgp; ! 445: size_t msgsz = uap->msgsz; ! 446: int msgflg = uap->msgflg; ! 447: int segs_needed, eval; ! 448: struct ucred *cred = p->p_ucred; ! 449: register struct msqid_ds *msqptr; ! 450: register struct msg *msghdr; ! 451: short next; ! 452: ! 453: #ifdef MSG_DEBUG_OK ! 454: printf("call to msgsnd(%d, 0x%x, %d, %d)\n", msqid, user_msgp, msgsz, ! 455: msgflg); ! 456: #endif ! 457: ! 458: msqid = IPCID_TO_IX(msqid); ! 459: ! 460: if (msqid < 0 || msqid >= msginfo.msgmni) { ! 461: #ifdef MSG_DEBUG_OK ! 462: printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid, ! 463: msginfo.msgmni); ! 464: #endif ! 465: return(EINVAL); ! 466: } ! 467: ! 468: msqptr = &msqids[msqid]; ! 469: if (msqptr->msg_qbytes == 0) { ! 470: #ifdef MSG_DEBUG_OK ! 471: printf("no such message queue id\n"); ! 472: #endif ! 473: return(EINVAL); ! 474: } ! 475: if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) { ! 476: #ifdef MSG_DEBUG_OK ! 477: printf("wrong sequence number\n"); ! 478: #endif ! 479: return(EINVAL); ! 480: } ! 481: ! 482: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_W))) { ! 483: #ifdef MSG_DEBUG_OK ! 484: printf("requester doesn't have write access\n"); ! 485: #endif ! 486: return(eval); ! 487: } ! 488: ! 489: segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz; ! 490: #ifdef MSG_DEBUG_OK ! 491: printf("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz, ! 492: segs_needed); ! 493: #endif ! 494: for (;;) { ! 495: int need_more_resources = 0; ! 496: ! 497: /* ! 498: * check msgsz ! 499: * (inside this loop in case msg_qbytes changes while we sleep) ! 500: */ ! 501: ! 502: if (msgsz > msqptr->msg_qbytes) { ! 503: #ifdef MSG_DEBUG_OK ! 504: printf("msgsz > msqptr->msg_qbytes\n"); ! 505: #endif ! 506: return(EINVAL); ! 507: } ! 508: ! 509: if (msqptr->msg_perm.mode & MSG_LOCKED) { ! 510: #ifdef MSG_DEBUG_OK ! 511: printf("msqid is locked\n"); ! 512: #endif ! 513: need_more_resources = 1; ! 514: } ! 515: if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) { ! 516: #ifdef MSG_DEBUG_OK ! 517: printf("msgsz + msg_cbytes > msg_qbytes\n"); ! 518: #endif ! 519: need_more_resources = 1; ! 520: } ! 521: if (segs_needed > nfree_msgmaps) { ! 522: #ifdef MSG_DEBUG_OK ! 523: printf("segs_needed > nfree_msgmaps\n"); ! 524: #endif ! 525: need_more_resources = 1; ! 526: } ! 527: if (free_msghdrs == NULL) { ! 528: #ifdef MSG_DEBUG_OK ! 529: printf("no more msghdrs\n"); ! 530: #endif ! 531: need_more_resources = 1; ! 532: } ! 533: ! 534: if (need_more_resources) { ! 535: int we_own_it; ! 536: ! 537: if ((msgflg & IPC_NOWAIT) != 0) { ! 538: #ifdef MSG_DEBUG_OK ! 539: printf("need more resources but caller doesn't want to wait\n"); ! 540: #endif ! 541: return(EAGAIN); ! 542: } ! 543: ! 544: if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) { ! 545: #ifdef MSG_DEBUG_OK ! 546: printf("we don't own the msqid_ds\n"); ! 547: #endif ! 548: we_own_it = 0; ! 549: } else { ! 550: /* Force later arrivals to wait for our ! 551: request */ ! 552: #ifdef MSG_DEBUG_OK ! 553: printf("we own the msqid_ds\n"); ! 554: #endif ! 555: msqptr->msg_perm.mode |= MSG_LOCKED; ! 556: we_own_it = 1; ! 557: } ! 558: #ifdef MSG_DEBUG_OK ! 559: printf("goodnight\n"); ! 560: #endif ! 561: eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH, ! 562: "msgwait", 0); ! 563: #ifdef MSG_DEBUG_OK ! 564: printf("good morning, eval=%d\n", eval); ! 565: #endif ! 566: if (we_own_it) ! 567: msqptr->msg_perm.mode &= ~MSG_LOCKED; ! 568: if (eval != 0) { ! 569: #ifdef MSG_DEBUG_OK ! 570: printf("msgsnd: interrupted system call\n"); ! 571: #endif ! 572: return(EINTR); ! 573: } ! 574: ! 575: /* ! 576: * Make sure that the msq queue still exists ! 577: */ ! 578: ! 579: if (msqptr->msg_qbytes == 0) { ! 580: #ifdef MSG_DEBUG_OK ! 581: printf("msqid deleted\n"); ! 582: #endif ! 583: /* The SVID says to return EIDRM. */ ! 584: #ifdef EIDRM ! 585: return(EIDRM); ! 586: #else ! 587: /* Unfortunately, BSD doesn't define that code ! 588: yet! */ ! 589: return(EINVAL); ! 590: #endif ! 591: } ! 592: ! 593: } else { ! 594: #ifdef MSG_DEBUG_OK ! 595: printf("got all the resources that we need\n"); ! 596: #endif ! 597: break; ! 598: } ! 599: } ! 600: ! 601: /* ! 602: * We have the resources that we need. ! 603: * Make sure! ! 604: */ ! 605: ! 606: if (msqptr->msg_perm.mode & MSG_LOCKED) ! 607: panic("msg_perm.mode & MSG_LOCKED"); ! 608: if (segs_needed > nfree_msgmaps) ! 609: panic("segs_needed > nfree_msgmaps"); ! 610: if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) ! 611: panic("msgsz + msg_cbytes > msg_qbytes"); ! 612: if (free_msghdrs == NULL) ! 613: panic("no more msghdrs"); ! 614: ! 615: /* ! 616: * Re-lock the msqid_ds in case we page-fault when copying in the ! 617: * message ! 618: */ ! 619: ! 620: if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) ! 621: panic("msqid_ds is already locked"); ! 622: msqptr->msg_perm.mode |= MSG_LOCKED; ! 623: ! 624: /* ! 625: * Allocate a message header ! 626: */ ! 627: ! 628: msghdr = free_msghdrs; ! 629: free_msghdrs = msghdr->msg_next; ! 630: msghdr->msg_spot = -1; ! 631: msghdr->msg_ts = msgsz; ! 632: ! 633: /* ! 634: * Allocate space for the message ! 635: */ ! 636: ! 637: while (segs_needed > 0) { ! 638: if (nfree_msgmaps <= 0) ! 639: panic("not enough msgmaps"); ! 640: if (free_msgmaps == -1) ! 641: panic("nil free_msgmaps"); ! 642: next = free_msgmaps; ! 643: if (next <= -1) ! 644: panic("next too low #1"); ! 645: if (next >= msginfo.msgseg) ! 646: panic("next out of range #1"); ! 647: #ifdef MSG_DEBUG_OK ! 648: printf("allocating segment %d to message\n", next); ! 649: #endif ! 650: free_msgmaps = msgmaps[next].next; ! 651: nfree_msgmaps--; ! 652: msgmaps[next].next = msghdr->msg_spot; ! 653: msghdr->msg_spot = next; ! 654: segs_needed--; ! 655: } ! 656: ! 657: /* ! 658: * Copy in the message type ! 659: */ ! 660: ! 661: if ((eval = copyin(user_msgp, &msghdr->msg_type, ! 662: sizeof(msghdr->msg_type))) != 0) { ! 663: #ifdef MSG_DEBUG_OK ! 664: printf("error %d copying the message type\n", eval); ! 665: #endif ! 666: msg_freehdr(msghdr); ! 667: msqptr->msg_perm.mode &= ~MSG_LOCKED; ! 668: wakeup((caddr_t)msqptr); ! 669: return(eval); ! 670: } ! 671: user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type); ! 672: ! 673: /* ! 674: * Validate the message type ! 675: */ ! 676: ! 677: if (msghdr->msg_type < 1) { ! 678: msg_freehdr(msghdr); ! 679: msqptr->msg_perm.mode &= ~MSG_LOCKED; ! 680: wakeup((caddr_t)msqptr); ! 681: #ifdef MSG_DEBUG_OK ! 682: printf("mtype (%d) < 1\n", msghdr->msg_type); ! 683: #endif ! 684: return(EINVAL); ! 685: } ! 686: ! 687: /* ! 688: * Copy in the message body ! 689: */ ! 690: ! 691: next = msghdr->msg_spot; ! 692: while (msgsz > 0) { ! 693: size_t tlen; ! 694: if (msgsz > msginfo.msgssz) ! 695: tlen = msginfo.msgssz; ! 696: else ! 697: tlen = msgsz; ! 698: if (next <= -1) ! 699: panic("next too low #2"); ! 700: if (next >= msginfo.msgseg) ! 701: panic("next out of range #2"); ! 702: if ((eval = copyin(user_msgp, &msgpool[next * msginfo.msgssz], ! 703: tlen)) != 0) { ! 704: #ifdef MSG_DEBUG_OK ! 705: printf("error %d copying in message segment\n", eval); ! 706: #endif ! 707: msg_freehdr(msghdr); ! 708: msqptr->msg_perm.mode &= ~MSG_LOCKED; ! 709: wakeup((caddr_t)msqptr); ! 710: return(eval); ! 711: } ! 712: msgsz -= tlen; ! 713: user_msgp = (char *)user_msgp + tlen; ! 714: next = msgmaps[next].next; ! 715: } ! 716: if (next != -1) ! 717: panic("didn't use all the msg segments"); ! 718: ! 719: /* ! 720: * We've got the message. Unlock the msqid_ds. ! 721: */ ! 722: ! 723: msqptr->msg_perm.mode &= ~MSG_LOCKED; ! 724: ! 725: /* ! 726: * Make sure that the msqid_ds is still allocated. ! 727: */ ! 728: ! 729: if (msqptr->msg_qbytes == 0) { ! 730: msg_freehdr(msghdr); ! 731: wakeup((caddr_t)msqptr); ! 732: /* The SVID says to return EIDRM. */ ! 733: #ifdef EIDRM ! 734: return(EIDRM); ! 735: #else ! 736: /* Unfortunately, BSD doesn't define that code yet! */ ! 737: return(EINVAL); ! 738: #endif ! 739: } ! 740: ! 741: /* ! 742: * Put the message into the queue ! 743: */ ! 744: ! 745: if (msqptr->msg_first == NULL) { ! 746: msqptr->msg_first = msghdr; ! 747: msqptr->msg_last = msghdr; ! 748: } else { ! 749: msqptr->msg_last->msg_next = msghdr; ! 750: msqptr->msg_last = msghdr; ! 751: } ! 752: msqptr->msg_last->msg_next = NULL; ! 753: ! 754: msqptr->msg_cbytes += msghdr->msg_ts; ! 755: msqptr->msg_qnum++; ! 756: msqptr->msg_lspid = p->p_pid; ! 757: msqptr->msg_stime = time_second; ! 758: ! 759: wakeup((caddr_t)msqptr); ! 760: p->p_retval[0] = 0; ! 761: return(0); ! 762: } ! 763: ! 764: #ifndef _SYS_SYSPROTO_H_ ! 765: struct msgrcv_args { ! 766: int msqid; ! 767: void *msgp; ! 768: size_t msgsz; ! 769: long msgtyp; ! 770: int msgflg; ! 771: }; ! 772: #endif ! 773: ! 774: int ! 775: msgrcv(p, uap) ! 776: struct proc *p; ! 777: register struct msgrcv_args *uap; ! 778: { ! 779: int msqid = uap->msqid; ! 780: void *user_msgp = uap->msgp; ! 781: size_t msgsz = uap->msgsz; ! 782: long msgtyp = uap->msgtyp; ! 783: int msgflg = uap->msgflg; ! 784: size_t len; ! 785: struct ucred *cred = p->p_ucred; ! 786: register struct msqid_ds *msqptr; ! 787: register struct msg *msghdr; ! 788: int eval; ! 789: short next; ! 790: ! 791: #ifdef MSG_DEBUG_OK ! 792: printf("call to msgrcv(%d, 0x%x, %d, %ld, %d)\n", msqid, user_msgp, ! 793: msgsz, msgtyp, msgflg); ! 794: #endif ! 795: ! 796: msqid = IPCID_TO_IX(msqid); ! 797: ! 798: if (msqid < 0 || msqid >= msginfo.msgmni) { ! 799: #ifdef MSG_DEBUG_OK ! 800: printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid, ! 801: msginfo.msgmni); ! 802: #endif ! 803: return(EINVAL); ! 804: } ! 805: ! 806: msqptr = &msqids[msqid]; ! 807: if (msqptr->msg_qbytes == 0) { ! 808: #ifdef MSG_DEBUG_OK ! 809: printf("no such message queue id\n"); ! 810: #endif ! 811: return(EINVAL); ! 812: } ! 813: if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) { ! 814: #ifdef MSG_DEBUG_OK ! 815: printf("wrong sequence number\n"); ! 816: #endif ! 817: return(EINVAL); ! 818: } ! 819: ! 820: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) { ! 821: #ifdef MSG_DEBUG_OK ! 822: printf("requester doesn't have read access\n"); ! 823: #endif ! 824: return(eval); ! 825: } ! 826: ! 827: msghdr = NULL; ! 828: while (msghdr == NULL) { ! 829: if (msgtyp == 0) { ! 830: msghdr = msqptr->msg_first; ! 831: if (msghdr != NULL) { ! 832: if (msgsz < msghdr->msg_ts && ! 833: (msgflg & MSG_NOERROR) == 0) { ! 834: #ifdef MSG_DEBUG_OK ! 835: printf("first message on the queue is too big (want %d, got %d)\n", ! 836: msgsz, msghdr->msg_ts); ! 837: #endif ! 838: return(E2BIG); ! 839: } ! 840: if (msqptr->msg_first == msqptr->msg_last) { ! 841: msqptr->msg_first = NULL; ! 842: msqptr->msg_last = NULL; ! 843: } else { ! 844: msqptr->msg_first = msghdr->msg_next; ! 845: if (msqptr->msg_first == NULL) ! 846: panic("msg_first/last messed up #1"); ! 847: } ! 848: } ! 849: } else { ! 850: struct msg *previous; ! 851: struct msg **prev; ! 852: ! 853: previous = NULL; ! 854: prev = &(msqptr->msg_first); ! 855: while ((msghdr = *prev) != NULL) { ! 856: /* ! 857: * Is this message's type an exact match or is ! 858: * this message's type less than or equal to ! 859: * the absolute value of a negative msgtyp? ! 860: * Note that the second half of this test can ! 861: * NEVER be true if msgtyp is positive since ! 862: * msg_type is always positive! ! 863: */ ! 864: ! 865: if (msgtyp == msghdr->msg_type || ! 866: msghdr->msg_type <= -msgtyp) { ! 867: #ifdef MSG_DEBUG_OK ! 868: printf("found message type %d, requested %d\n", ! 869: msghdr->msg_type, msgtyp); ! 870: #endif ! 871: if (msgsz < msghdr->msg_ts && ! 872: (msgflg & MSG_NOERROR) == 0) { ! 873: #ifdef MSG_DEBUG_OK ! 874: printf("requested message on the queue is too big (want %d, got %d)\n", ! 875: msgsz, msghdr->msg_ts); ! 876: #endif ! 877: return(E2BIG); ! 878: } ! 879: *prev = msghdr->msg_next; ! 880: if (msghdr == msqptr->msg_last) { ! 881: if (previous == NULL) { ! 882: if (prev != ! 883: &msqptr->msg_first) ! 884: panic("msg_first/last messed up #2"); ! 885: msqptr->msg_first = ! 886: NULL; ! 887: msqptr->msg_last = ! 888: NULL; ! 889: } else { ! 890: if (prev == ! 891: &msqptr->msg_first) ! 892: panic("msg_first/last messed up #3"); ! 893: msqptr->msg_last = ! 894: previous; ! 895: } ! 896: } ! 897: break; ! 898: } ! 899: previous = msghdr; ! 900: prev = &(msghdr->msg_next); ! 901: } ! 902: } ! 903: ! 904: /* ! 905: * We've either extracted the msghdr for the appropriate ! 906: * message or there isn't one. ! 907: * If there is one then bail out of this loop. ! 908: */ ! 909: ! 910: if (msghdr != NULL) ! 911: break; ! 912: ! 913: /* ! 914: * Hmph! No message found. Does the user want to wait? ! 915: */ ! 916: ! 917: if ((msgflg & IPC_NOWAIT) != 0) { ! 918: #ifdef MSG_DEBUG_OK ! 919: printf("no appropriate message found (msgtyp=%d)\n", ! 920: msgtyp); ! 921: #endif ! 922: /* The SVID says to return ENOMSG. */ ! 923: #ifdef ENOMSG ! 924: return(ENOMSG); ! 925: #else ! 926: /* Unfortunately, BSD doesn't define that code yet! */ ! 927: return(EAGAIN); ! 928: #endif ! 929: } ! 930: ! 931: /* ! 932: * Wait for something to happen ! 933: */ ! 934: ! 935: #ifdef MSG_DEBUG_OK ! 936: printf("msgrcv: goodnight\n"); ! 937: #endif ! 938: eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH, "msgwait", ! 939: 0); ! 940: #ifdef MSG_DEBUG_OK ! 941: printf("msgrcv: good morning (eval=%d)\n", eval); ! 942: #endif ! 943: ! 944: if (eval != 0) { ! 945: #ifdef MSG_DEBUG_OK ! 946: printf("msgsnd: interrupted system call\n"); ! 947: #endif ! 948: return(EINTR); ! 949: } ! 950: ! 951: /* ! 952: * Make sure that the msq queue still exists ! 953: */ ! 954: ! 955: if (msqptr->msg_qbytes == 0 || ! 956: msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) { ! 957: #ifdef MSG_DEBUG_OK ! 958: printf("msqid deleted\n"); ! 959: #endif ! 960: /* The SVID says to return EIDRM. */ ! 961: #ifdef EIDRM ! 962: return(EIDRM); ! 963: #else ! 964: /* Unfortunately, BSD doesn't define that code yet! */ ! 965: return(EINVAL); ! 966: #endif ! 967: } ! 968: } ! 969: ! 970: /* ! 971: * Return the message to the user. ! 972: * ! 973: * First, do the bookkeeping (before we risk being interrupted). ! 974: */ ! 975: ! 976: msqptr->msg_cbytes -= msghdr->msg_ts; ! 977: msqptr->msg_qnum--; ! 978: msqptr->msg_lrpid = p->p_pid; ! 979: msqptr->msg_rtime = time_second; ! 980: ! 981: /* ! 982: * Make msgsz the actual amount that we'll be returning. ! 983: * Note that this effectively truncates the message if it is too long ! 984: * (since msgsz is never increased). ! 985: */ ! 986: ! 987: #ifdef MSG_DEBUG_OK ! 988: printf("found a message, msgsz=%d, msg_ts=%d\n", msgsz, ! 989: msghdr->msg_ts); ! 990: #endif ! 991: if (msgsz > msghdr->msg_ts) ! 992: msgsz = msghdr->msg_ts; ! 993: ! 994: /* ! 995: * Return the type to the user. ! 996: */ ! 997: ! 998: eval = copyout((caddr_t)&(msghdr->msg_type), user_msgp, ! 999: sizeof(msghdr->msg_type)); ! 1000: if (eval != 0) { ! 1001: #ifdef MSG_DEBUG_OK ! 1002: printf("error (%d) copying out message type\n", eval); ! 1003: #endif ! 1004: msg_freehdr(msghdr); ! 1005: wakeup((caddr_t)msqptr); ! 1006: return(eval); ! 1007: } ! 1008: user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type); ! 1009: ! 1010: /* ! 1011: * Return the segments to the user ! 1012: */ ! 1013: ! 1014: next = msghdr->msg_spot; ! 1015: for (len = 0; len < msgsz; len += msginfo.msgssz) { ! 1016: size_t tlen; ! 1017: ! 1018: if (msgsz > msginfo.msgssz) ! 1019: tlen = msginfo.msgssz; ! 1020: else ! 1021: tlen = msgsz; ! 1022: if (next <= -1) ! 1023: panic("next too low #3"); ! 1024: if (next >= msginfo.msgseg) ! 1025: panic("next out of range #3"); ! 1026: eval = copyout((caddr_t)&msgpool[next * msginfo.msgssz], ! 1027: user_msgp, tlen); ! 1028: if (eval != 0) { ! 1029: #ifdef MSG_DEBUG_OK ! 1030: printf("error (%d) copying out message segment\n", ! 1031: eval); ! 1032: #endif ! 1033: msg_freehdr(msghdr); ! 1034: wakeup((caddr_t)msqptr); ! 1035: return(eval); ! 1036: } ! 1037: user_msgp = (char *)user_msgp + tlen; ! 1038: next = msgmaps[next].next; ! 1039: } ! 1040: ! 1041: /* ! 1042: * Done, return the actual number of bytes copied out. ! 1043: */ ! 1044: ! 1045: msg_freehdr(msghdr); ! 1046: wakeup((caddr_t)msqptr); ! 1047: p->p_retval[0] = msgsz; ! 1048: return(0); ! 1049: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.