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