|
|
1.1 ! root 1: /* ! 2: * System V Compatible Messaging ! 3: * ! 4: * This module provides System V compatible messaging operations. ! 5: */ ! 6: #include <sys/coherent.h> ! 7: #include <sys/sched.h> ! 8: #include <sys/types.h> ! 9: #include <sys/uproc.h> ! 10: #include <errno.h> ! 11: #include <sys/stat.h> ! 12: #include <sys/con.h> ! 13: #include <sys/seg.h> ! 14: #include <sys/msg.h> ! 15: ! 16: /* ! 17: * Global Message Parameters. We want them to be patchable. ! 18: */ ! 19: unsigned NMSQID = 50; /* maximum number of message queues */ ! 20: unsigned NMSQB = 4096; /* default maximum queue size in bytes */ ! 21: unsigned NMSG = 40; /* maximum number of messages per queue */ ! 22: unsigned NMSC = 2048; /* message text size */ ! 23: ! 24: #ifdef TRACER ! 25: int dballoc = 0; /* For debug only */ ! 26: int dbfree = 0; ! 27: #endif ! 28: ! 29: /* Message Information */ ! 30: struct msqid_ds *msqs = NULL; /* Array of message queues */ ! 31: GATE *msg_gate; /* Message gates */ ! 32: char **msg_map; /* Memory map */ ! 33: ! 34: /* ! 35: * Msgctl - Message Control Operations. ! 36: */ ! 37: umsgctl(qid, cmd, buf) ! 38: int qid; ! 39: int cmd; ! 40: struct msqid_ds *buf; ! 41: { ! 42: register struct msqid_ds *qp; /* message queues */ ! 43: register struct msg *mp; /* single message queue */ ! 44: unsigned short n; /* temporary variable */ ! 45: ! 46: /* Validate qid */ ! 47: if (qid < 0) { ! 48: u.u_error = EINVAL; ! 49: return -1; ! 50: } ! 51: qp = &msqs[qid % NMSQID]; ! 52: ! 53: /* Validate queue existence.*/ ! 54: if (qp->msg_perm.seq != qid || (qp->msg_perm.mode & IPC_ALLOC) == 0) { ! 55: u.u_error = EINVAL; ! 56: return -1; ! 57: } ! 58: ! 59: switch (cmd) { ! 60: case IPC_STAT: ! 61: /* Validate access authority. */ ! 62: if ((ipcaccess(&qp->msg_perm) & MSG_R) == 0) { ! 63: u.u_error = EACCES; ! 64: break; ! 65: } ! 66: ! 67: /* Copy queue info to user buffer */ ! 68: kucopy(qp, buf, sizeof(struct msqid_ds)); ! 69: break; ! 70: case IPC_SET: ! 71: /* Validate modify authority. */ ! 72: if ((u.u_uid != 0) && (u.u_uid != qp->msg_perm.uid)) { ! 73: u.u_error = EPERM; ! 74: break; ! 75: } ! 76: ! 77: /* ! 78: * Get desired queue size. ! 79: */ ! 80: n = getusd(&(buf->msg_qbytes)); ! 81: if (u.u_error) ! 82: break; ! 83: ! 84: /* ! 85: * Only super-user can increase queue size. ! 86: */ ! 87: if ((u.u_uid != 0) && (n > qp->msg_qbytes)) { ! 88: u.u_error = EPERM; ! 89: break; ! 90: } ! 91: ! 92: /* ! 93: * Set queue parameters. ! 94: */ ! 95: qp->msg_perm.uid = getusd(&(buf->msg_perm.uid)); ! 96: qp->msg_perm.gid = getusd(&(buf->msg_perm.gid)); ! 97: qp->msg_perm.mode &= ~0777; ! 98: qp->msg_perm.mode |= getusd(&(buf->msg_perm.mode)) & 0777; ! 99: /* We may want to change the max size of a single message too. ! 100: * It is not obvious how to do it. There is no ! 101: * description in SVID. So it is possible that at some point ! 102: * the size of the single message happens to be greater than ! 103: * the size of message queue ;-( ! 104: */ ! 105: qp->msg_qbytes = NMSQB = n; ! 106: break; ! 107: ! 108: case IPC_RMID: ! 109: /* Validate removal authority. */ ! 110: if ((u.u_uid != 0) && (u.u_uid != qp->msg_perm.uid)) { ! 111: u.u_error = EPERM; ! 112: break; ! 113: } ! 114: /* Free all messages on the queue being removed. */ ! 115: while (mp = qp->msg_first) { ! 116: qp->msg_first = mp->msg_next; ! 117: T_MSGQ(0x01, dballoc -= sizeof(struct msg)); ! 118: msgfree(mp); ! 119: } ! 120: T_MSGQ(0x01, printf("F%d", dballoc)); ! 121: ! 122: /* Reset queue parameters. */ ! 123: qp->msg_last = NULL; ! 124: qp->msg_qnum = 0; ! 125: qp->msg_cbytes = 0; ! 126: qp->msg_perm.mode = 0; ! 127: /* Set last change time */ ! 128: qp->msg_ctime = timer.t_time; ! 129: /* We have to pick up a new unique sequence number. ! 130: * There is a "wrap around bug". But, it is BCS. ! 131: */ ! 132: qp->msg_perm.seq += (unsigned short) 50; ! 133: break; ! 134: default: ! 135: u.u_error = EINVAL; ! 136: } ! 137: ! 138: if (u.u_error) ! 139: return -1; ! 140: ! 141: return 0; ! 142: } ! 143: ! 144: /* ! 145: * Msgget - Get set of messages ! 146: */ ! 147: umsgget(mykey, msgflg) ! 148: key_t mykey; ! 149: int msgflg; ! 150: { ! 151: register struct msqid_ds *qp; ! 152: register struct msqid_ds *freeidp = NULL; ! 153: int rwmode; ! 154: ! 155: /* Init message queues on the first msgget */ ! 156: if (msqs == NULL) ! 157: if (msginit()) { ! 158: u.u_error = ENOSPC; ! 159: return -1; ! 160: } ! 161: /* Extract desired access mode from flags. */ ! 162: rwmode = msgflg & 0777; /* 0666 ??? */ ! 163: T_MSGQ(0x02, printf("U%o", rwmode)); ! 164: /* Search for desired message queue [also for first free queue]. */ ! 165: for (qp = msqs; qp < msqs + NMSQID; qp++) { ! 166: /* Look for an older free queue */ ! 167: if (!(qp->msg_perm.mode & IPC_ALLOC)) { ! 168: if (freeidp == NULL ! 169: || freeidp->msg_ctime > qp->msg_ctime) ! 170: freeidp = qp; ! 171: continue; ! 172: } ! 173: if (mykey == IPC_PRIVATE) { /* creat a new queue */ ! 174: if (msgflg & IPC_EXCL) /* unique new queue */ ! 175: if (mykey == qp->msg_perm.key) { ! 176: u.u_error = EEXIST;/* We cannot creat */ ! 177: return -1; /* exclusive queue */ ! 178: } ! 179: continue; ! 180: } ! 181: if (qp->msg_perm.key != mykey) ! 182: continue; ! 183: if (mykey == qp->msg_perm.key) { /* found! */ ! 184: if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) { ! 185: u.u_error = EEXIST; /* We cannot creat */ ! 186: return -1; /* exclusive queue */ ! 187: } ! 188: /* PERMISSIONS */ ! 189: /* For super-user or if mode is 0 */ ! 190: if (u.u_uid == 0 || !rwmode) ! 191: return qp->msg_perm.seq; ! 192: /* For owner or creator */ ! 193: T_MSGQ(0x02, printf("Q%o", qp->msg_perm.mode)); ! 194: if (u.u_uid == qp->msg_perm.uid ! 195: || u.u_uid == qp->msg_perm.cuid) ! 196: if ( ! 197: ((rwmode & 0600)<=(qp->msg_perm.mode & 0600)) ! 198: &&((rwmode & 060)<=(qp->msg_perm.mode & 060)) ! 199: &&((rwmode & 06)<=(qp->msg_perm.mode & 06))) ! 200: return qp->msg_perm.seq; ! 201: else { ! 202: u.u_error = EACCES; ! 203: return -1; ! 204: } ! 205: /* For group */ ! 206: if (u.u_gid == qp->msg_perm.gid ! 207: || u.u_gid == qp->msg_perm.cgid) ! 208: if (((rwmode & 0660)<=(qp->msg_perm.mode & 060)) ! 209: &&((rwmode & 06)<=(qp->msg_perm.mode & 06))) ! 210: return qp->msg_perm.seq; ! 211: else { ! 212: u.u_error = EACCES; ! 213: return -1; ! 214: } ! 215: /* For the rest of the world */ ! 216: if ((rwmode & 0666) <= (qp->msg_perm.mode & 06)) ! 217: return qp->msg_perm.seq; ! 218: else { ! 219: u.u_error = EACCES; ! 220: return -1; ! 221: } ! 222: } ! 223: } ! 224: ! 225: /* Creat a new queue */ ! 226: if (!(msgflg & IPC_CREAT)) { ! 227: u.u_error = ENOENT; ! 228: return -1; ! 229: } ! 230: if ((qp = freeidp) == NULL) { ! 231: u.u_error = ENOSPC; ! 232: return -1; ! 233: } ! 234: /* Set new queue */ ! 235: qp->msg_ctime = timer.t_time; ! 236: qp->msg_perm.cuid = qp->msg_perm.uid = u.u_uid; ! 237: qp->msg_perm.cgid = qp->msg_perm.gid = u.u_gid; ! 238: qp->msg_perm.mode = rwmode | IPC_ALLOC; ! 239: qp->msg_qnum = qp->msg_lspid = qp->msg_lrpid = qp->msg_stime ! 240: = qp->msg_rtime = 0; ! 241: qp->msg_perm.key = mykey; ! 242: ! 243: return qp->msg_perm.seq; ! 244: } ! 245: ! 246: /* ! 247: * Allocate space for the message queues and gates. ! 248: * Initialize message queue headers ! 249: * Return -1 on error. ! 250: */ ! 251: msginit() ! 252: { ! 253: struct msqid_ds *qp; ! 254: ! 255: T_MSGQ(0x01, printf("A%d",dballoc += sizeof(struct msqid_ds) * NMSQID)); ! 256: ! 257: /* Allocate space for message headers */ ! 258: if ((msqs = ! 259: (struct msqid_ds *) kalloc(sizeof(struct msqid_ds) * NMSQID)) == NULL) ! 260: return -1; ! 261: ! 262: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(GATE) * NMSQID)); ! 263: ! 264: /* Allocate space for message gates */ ! 265: if ((msg_gate = (GATE *) kalloc(sizeof(GATE) * NMSQID)) == NULL) { ! 266: kfree(msqs); ! 267: msqs = NULL; ! 268: return -1; ! 269: } ! 270: ! 271: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(char *) * NMSQID * NMSG)); ! 272: ! 273: /* Allocate space for the message map */ ! 274: if ((msg_map = kalloc(sizeof(char *) * NMSQID * NMSG)) == NULL) { ! 275: kfree(msqs); ! 276: msqs = NULL; ! 277: kfree(msg_gate); ! 278: return -1; ! 279: } ! 280: /* Clear gate and map areas */ ! 281: kclear(msg_gate, sizeof(GATE) * NMSQID); ! 282: kclear(msg_map, sizeof(char *) * NMSQID * NMSG); ! 283: /* Set initial queue values */ ! 284: for (qp = msqs; qp < msqs + NMSQID; qp++) { ! 285: qp->msg_first = NULL; /* First and last pointers to */ ! 286: qp->msg_last = NULL; /* message queue */ ! 287: qp->msg_cbytes = 0; /* Number of bytes in queue */ ! 288: qp->msg_qnum = 0; /* Number of messages in queue */ ! 289: qp->msg_qbytes = NMSQB; /* Max size of a queue */ ! 290: qp->msg_lspid = 0; /* Pid of last msgsnd */ ! 291: qp->msg_lrpid = 0; /* Pid of last msgrcv */ ! 292: qp->msg_stime = 0; /* Last msgsnd time */ ! 293: qp->msg_rtime = 0; /* Last msgrcv time */ ! 294: qp->msg_ctime = timer.t_time; /* Last change time */ ! 295: qp->msg_perm.seq = qp - msqs; ! 296: qp->msg_perm.mode = 0; ! 297: } ! 298: return 0; ! 299: } ! 300: ! 301: /* ! 302: * Remove the message. Clear message text and header. Reset values in ! 303: * message map. ! 304: */ ! 305: msgfree(mp) ! 306: struct msg *mp; /* Message header to be remove */ ! 307: { ! 308: ! 309: kfree(msg_map[mp->msg_spot]); ! 310: msg_map[mp->msg_spot] = NULL; ! 311: kfree(mp); ! 312: T_MSGQ(0x01, printf("F%d", dballoc-=(mp->msg_ts + sizeof(struct msg)))); ! 313: } ! 314: ! 315: /* ! 316: * Send a Message ! 317: */ ! 318: umsgsnd(qid, bufp, msgsz, msgflg) ! 319: int qid; /* queue id */ ! 320: struct msgbuf *bufp; /* message buffer */ ! 321: int msgsz, /* message size */ ! 322: msgflg; /* flags */ ! 323: { ! 324: register struct msqid_ds *qp; /* message queue */ ! 325: register struct msg *mp, /* message struct */ ! 326: *tmp; ! 327: int q_num; /* number of a queue */ ! 328: int i_spot; /* # of empty entry in map */ ! 329: ! 330: /* Validate queue identifier. */ ! 331: for (qp = msqs; qp < msqs + NMSQID; qp++) ! 332: if (qp->msg_perm.seq == qid) /* found */ ! 333: break; ! 334: ! 335: q_num = qp - msqs; ! 336: /* qid is not a valid qid identifier */ ! 337: if (q_num >= NMSQID) { ! 338: u.u_error = EINVAL; ! 339: return -1; ! 340: } ! 341: ! 342: if (!(ipcaccess(&qp->msg_perm) & MSG_W)) { /* can't send mesg */ ! 343: u.u_error = EACCES; ! 344: return -1; ! 345: } ! 346: ! 347: /* Check if message has a valid message type and size. ! 348: * The comparisson with NMSQB was done because user could ! 349: * reduce this value. ! 350: */ ! 351: if (bufp->mtype < 1 || msgsz < 0 || msgsz > NMSC || msgsz > NMSQB) { ! 352: u.u_error = EACCES; ! 353: return -1; ! 354: } ! 355: ! 356: /* Now we have a valid message. Check if we can send it. */ ! 357: lock(msg_gate[q_num]); /* Lock it to avoid race condition */ ! 358: while (qp->msg_qnum >= NMSG || ! 359: qp->msg_qbytes < (qp->msg_cbytes + msgsz)) { ! 360: if (msgflg & IPC_NOWAIT) { ! 361: u.u_error = EAGAIN; ! 362: unlock(msg_gate[q_num]); ! 363: return -1; ! 364: } ! 365: /* We have to wait here */ ! 366: qp->msg_perm.mode |= MSG_WWAIT; ! 367: unlock(msg_gate[q_num]); ! 368: x_sleep(qp, pritty, slpriSigCatch, "umsgsnd"); ! 369: ! 370: /* Abort if a signal was received */ ! 371: if (SELF->p_ssig && nondsig()) { ! 372: u.u_error = EINTR; ! 373: return -1; ! 374: } ! 375: ! 376: /* Abort if the message queue was removed. */ ! 377: if (qid != qp->msg_perm.seq) { ! 378: u.u_error = EINVAL; ! 379: return -1; ! 380: } ! 381: lock(msg_gate[q_num]); ! 382: } ! 383: ! 384: /* Find empty entry in message map */ ! 385: for (i_spot = 0; i_spot < NMSQID * NMSG; i_spot++) ! 386: if (msg_map[i_spot] == NULL) ! 387: break; ! 388: /* It cannot happen when we do not have empty entry in map, ! 389: * but let check it. ! 390: */ ! 391: if (i_spot >= NMSQID * NMSG) { ! 392: u.u_error = ENOSPC; ! 393: return -1; ! 394: } ! 395: ! 396: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(struct msg))); ! 397: ! 398: /* Get space for the message header */ ! 399: if ((mp = kalloc(sizeof(struct msg))) == NULL) { ! 400: unlock(msg_gate[q_num]); ! 401: u.u_error = ENOSPC; ! 402: return -1; ! 403: } ! 404: ! 405: T_MSGQ(0x01, printf("A%d", dballoc += msgsz)); ! 406: ! 407: /* Alloc space for the message text */ ! 408: if ((msg_map[i_spot] = kalloc(msgsz)) == NULL) { ! 409: kfree(mp); ! 410: unlock(msg_gate[q_num]); ! 411: u.u_error = ENOSPC; ! 412: return -1; ! 413: } ! 414: ! 415: mp->msg_next = NULL; ! 416: mp->msg_ts = msgsz; ! 417: /* The map address is a number of msg_map array element */ ! 418: mp->msg_spot = i_spot; ! 419: ! 420: /* Transfer the message type and text.*/ ! 421: if (ukcopy(&(bufp->mtype), &(mp->msg_type), sizeof(mp->msg_type)) != ! 422: sizeof(mp->msg_type)) ! 423: u.u_error = EFAULT; ! 424: if (ukcopy(&bufp->mtext[0], msg_map[i_spot], msgsz) != msgsz) ! 425: u.u_error = EFAULT; ! 426: if (u.u_error) { ! 427: msgfree(mp); ! 428: unlock(msg_gate[q_num]); ! 429: return -1; ! 430: } ! 431: ! 432: /* Move the message to the desired queue. */ ! 433: if (qp->msg_first == NULL) /* This is the first message per queue */ ! 434: qp->msg_first = qp->msg_last = mp; ! 435: else { /* There are messages */ ! 436: /* Find last message in gueue */ ! 437: for (tmp = qp->msg_first; ; tmp = tmp->msg_next) ! 438: if (tmp->msg_next == NULL) ! 439: break; ! 440: qp->msg_last = tmp->msg_next = mp; ! 441: } ! 442: mp->msg_next = NULL; ! 443: ! 444: /* Update queue statistics. */ ! 445: qp->msg_cbytes += msgsz; ! 446: qp->msg_qnum++; ! 447: qp->msg_lspid = SELF->p_pid; ! 448: qp->msg_stime = timer.t_time; ! 449: ! 450: /* Unlock queue and wake processes waiting to receive. */ ! 451: unlock(msg_gate[q_num]); ! 452: if (qp->msg_perm.mode & MSG_RWAIT) { ! 453: qp->msg_perm.mode &= ~MSG_RWAIT; ! 454: wakeup(qp); ! 455: } ! 456: return 0; ! 457: } ! 458: ! 459: /* ! 460: * Receive a Message ! 461: */ ! 462: umsgrcv(qid, bufp, msgsz, msgtyp, msgflg) ! 463: int qid; /* Message queue id */ ! 464: struct msgbuf *bufp; /* Message buffer */ ! 465: int msgsz; /* Message text size */ ! 466: long msgtyp; /* Message type */ ! 467: int msgflg; /* Message flag */ ! 468: { ! 469: register struct msqid_ds *qp; /* queue headers */ ! 470: register struct msg *mp, /* message headers */ ! 471: *prev; ! 472: int q_num; /* queue number */ ! 473: int i_spot; ! 474: ! 475: /* Validate queue identifier. */ ! 476: if (qid < 0 || msqs == NULL) { ! 477: u.u_error = EINVAL; ! 478: return -1; ! 479: } ! 480: q_num = qid % NMSQID; ! 481: qp = &msqs[q_num]; ! 482: ! 483: /* Validate queue existence.*/ ! 484: if (qp->msg_perm.seq != qid || (qp->msg_perm.mode & IPC_ALLOC) == 0) { ! 485: u.u_error = EINVAL; ! 486: return -1; ! 487: } ! 488: ! 489: /* Permission denied */ ! 490: if ((ipcaccess(&qp->msg_perm) & MSG_R) == 0) { ! 491: u.u_error = EACCES; ! 492: return -1; ! 493: } ! 494: ! 495: /* Wait for message */ ! 496: lock(msg_gate[q_num]); ! 497: for (;;) { ! 498: prev = NULL; ! 499: mp = qp->msg_first; ! 500: /* Find mesg of type <= abs(msgtyp) */ ! 501: if (msgtyp < 0) { ! 502: struct msg *qmin; /* Message with lowest mtype */ ! 503: struct msg *xprev; /* Previous message */ ! 504: ! 505: qmin = NULL; ! 506: xprev = prev; ! 507: msgtyp = -msgtyp; ! 508: ! 509: for (; mp != NULL; prev = mp, mp = mp->msg_next) { ! 510: if (mp->msg_type > msgtyp) ! 511: continue; ! 512: if (qmin == NULL ! 513: || mp->msg_type < qmin->msg_type) { ! 514: xprev = prev; ! 515: qmin = mp; ! 516: } ! 517: } ! 518: prev = xprev; ! 519: mp = qmin; ! 520: msgtyp = -msgtyp; ! 521: } else if (msgtyp > 0) { /* Find message of type == msgtyp */ ! 522: while (mp != NULL && mp->msg_type != msgtyp) { ! 523: prev = mp; ! 524: mp = mp->msg_next; ! 525: } ! 526: } else /* Else take first message */ ! 527: mp = qp->msg_first; ! 528: ! 529: if (mp != NULL) /* Found */ ! 530: break; ! 531: ! 532: /* Can't wait to receive mesg */ ! 533: if (msgflg & IPC_NOWAIT) { ! 534: u.u_error = EAGAIN; ! 535: unlock(msg_gate[q_num]); ! 536: return -1; ! 537: } ! 538: ! 539: /* We can go sleep now */ ! 540: qp->msg_perm.mode |= MSG_RWAIT; ! 541: unlock(msg_gate[q_num]); ! 542: x_sleep(qp, pritty, slpriSigCatch, "umsgrcv"); ! 543: ! 544: /* Signal received */ ! 545: if (SELF->p_ssig && nondsig()) { ! 546: u.u_error = EINTR; ! 547: return -1; ! 548: } ! 549: ! 550: /* Not same q anymore */ ! 551: if (qid != qp->msg_perm.seq) { ! 552: u.u_error = EINVAL; ! 553: return -1; ! 554: } ! 555: lock(msg_gate[q_num]); ! 556: } ! 557: ! 558: /* Ensure entire message can be transferred, or MSG_NOERROR asserted.*/ ! 559: if (msgsz < mp->msg_ts && (msgflg & MSG_NOERROR) == 0) { ! 560: unlock(msg_gate[q_num]); ! 561: u.u_error = E2BIG; ! 562: return -1; ! 563: } ! 564: ! 565: /* Transfer message data */ ! 566: if (msgsz > mp->msg_ts) ! 567: msgsz = mp->msg_ts; ! 568: ! 569: kucopy(&(mp->msg_type), &(bufp->mtype), sizeof(mp->msg_type)); ! 570: ! 571: i_spot = mp->msg_spot; ! 572: if (kucopy(msg_map[i_spot], bufp->mtext, msgsz) != msgsz) ! 573: u.u_error = EFAULT; ! 574: ! 575: /* Abort if address fault occurred during transfer. */ ! 576: if (u.u_error) { ! 577: unlock(msg_gate[q_num]); ! 578: return -1; ! 579: } ! 580: /* Remove message from queue */ ! 581: if (prev != NULL) ! 582: prev->msg_next = mp->msg_next; ! 583: else ! 584: qp->msg_first = mp->msg_next; ! 585: ! 586: if (qp->msg_last == mp) ! 587: qp->msg_last = prev; ! 588: ! 589: ! 590: /* Update queue statistics */ ! 591: qp->msg_cbytes -= mp->msg_ts; ! 592: qp->msg_qnum--; ! 593: qp->msg_lrpid = SELF->p_pid; ! 594: qp->msg_rtime = timer.t_time; ! 595: ! 596: /* free message */ ! 597: msgfree(mp); ! 598: ! 599: unlock(msg_gate[q_num]); ! 600: /* Wakeup processes waiting to send. */ ! 601: if (qp->msg_perm.mode & MSG_WWAIT) { ! 602: qp->msg_perm.mode &= ~MSG_WWAIT; ! 603: wakeup(qp); ! 604: } ! 605: return msgsz; ! 606: } ! 607:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.