|
|
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 <sys/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: ! 184: if (mykey == qp->msg_perm.key) { /* found! */ ! 185: if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) { ! 186: u.u_error = EEXIST; /* We cannot creat */ ! 187: return -1; /* exclusive queue */ ! 188: } ! 189: ! 190: /* PERMISSIONS */ ! 191: /* For super-user or if mode is 0 */ ! 192: if (u.u_uid == 0 || !rwmode) ! 193: return qp->msg_perm.seq; ! 194: ! 195: /* For owner or creator */ ! 196: T_MSGQ(0x02, printf("Q%o", qp->msg_perm.mode)); ! 197: if (u.u_uid == qp->msg_perm.uid ! 198: || u.u_uid == qp->msg_perm.cuid) { ! 199: if ((rwmode & 0600) & (qp->msg_perm.mode & 0600)) ! 200: return qp->msg_perm.seq; ! 201: else { ! 202: u.u_error = EACCES; ! 203: return -1; ! 204: } ! 205: } ! 206: ! 207: /* For group */ ! 208: if (u.u_gid == qp->msg_perm.gid ! 209: || u.u_gid == qp->msg_perm.cgid) { ! 210: if ((rwmode & 060) & (qp->msg_perm.mode & 060)) ! 211: return qp->msg_perm.seq; ! 212: else { ! 213: u.u_error = EACCES; ! 214: return -1; ! 215: } ! 216: } ! 217: ! 218: /* For the rest of the world */ ! 219: if ((rwmode & 06) & (qp->msg_perm.mode & 06)) ! 220: return qp->msg_perm.seq; ! 221: else { ! 222: u.u_error = EACCES; ! 223: return -1; ! 224: } ! 225: } ! 226: } ! 227: ! 228: /* Creat a new queue */ ! 229: if (!(msgflg & IPC_CREAT)) { ! 230: u.u_error = ENOENT; ! 231: return -1; ! 232: } ! 233: if ((qp = freeidp) == NULL) { ! 234: u.u_error = ENOSPC; ! 235: return -1; ! 236: } ! 237: /* Set new queue */ ! 238: qp->msg_ctime = timer.t_time; ! 239: qp->msg_perm.cuid = qp->msg_perm.uid = u.u_uid; ! 240: qp->msg_perm.cgid = qp->msg_perm.gid = u.u_gid; ! 241: qp->msg_perm.mode = rwmode | IPC_ALLOC; ! 242: qp->msg_qnum = qp->msg_lspid = qp->msg_lrpid = qp->msg_stime ! 243: = qp->msg_rtime = 0; ! 244: qp->msg_perm.key = mykey; ! 245: ! 246: return qp->msg_perm.seq; ! 247: } ! 248: ! 249: /* ! 250: * Allocate space for the message queues and gates. ! 251: * Initialize message queue headers ! 252: * Return -1 on error. ! 253: */ ! 254: msginit() ! 255: { ! 256: struct msqid_ds *qp; ! 257: ! 258: T_MSGQ(0x01, printf("A%d",dballoc += sizeof(struct msqid_ds) * NMSQID)); ! 259: ! 260: /* Allocate space for message headers */ ! 261: if ((msqs = ! 262: (struct msqid_ds *) kalloc(sizeof(struct msqid_ds) * NMSQID)) == NULL) ! 263: return -1; ! 264: ! 265: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(GATE) * NMSQID)); ! 266: ! 267: /* Allocate space for message gates */ ! 268: if ((msg_gate = (GATE *) kalloc(sizeof(GATE) * NMSQID)) == NULL) { ! 269: kfree(msqs); ! 270: msqs = NULL; ! 271: return -1; ! 272: } ! 273: ! 274: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(char *) * NMSQID * NMSG)); ! 275: ! 276: /* Allocate space for the message map */ ! 277: if ((msg_map = kalloc(sizeof(char *) * NMSQID * NMSG)) == NULL) { ! 278: kfree(msqs); ! 279: msqs = NULL; ! 280: kfree(msg_gate); ! 281: return -1; ! 282: } ! 283: /* Clear gate and map areas */ ! 284: kclear(msg_gate, sizeof(GATE) * NMSQID); ! 285: kclear(msg_map, sizeof(char *) * NMSQID * NMSG); ! 286: /* Set initial queue values */ ! 287: for (qp = msqs; qp < msqs + NMSQID; qp++) { ! 288: qp->msg_first = NULL; /* First and last pointers to */ ! 289: qp->msg_last = NULL; /* message queue */ ! 290: qp->msg_cbytes = 0; /* Number of bytes in queue */ ! 291: qp->msg_qnum = 0; /* Number of messages in queue */ ! 292: qp->msg_qbytes = NMSQB; /* Max size of a queue */ ! 293: qp->msg_lspid = 0; /* Pid of last msgsnd */ ! 294: qp->msg_lrpid = 0; /* Pid of last msgrcv */ ! 295: qp->msg_stime = 0; /* Last msgsnd time */ ! 296: qp->msg_rtime = 0; /* Last msgrcv time */ ! 297: qp->msg_ctime = timer.t_time; /* Last change time */ ! 298: qp->msg_perm.seq = qp - msqs; ! 299: qp->msg_perm.mode = 0; ! 300: } ! 301: return 0; ! 302: } ! 303: ! 304: /* ! 305: * Remove the message. Clear message text and header. Reset values in ! 306: * message map. ! 307: */ ! 308: msgfree(mp) ! 309: struct msg *mp; /* Message header to be remove */ ! 310: { ! 311: ! 312: kfree(msg_map[mp->msg_spot]); ! 313: msg_map[mp->msg_spot] = NULL; ! 314: kfree(mp); ! 315: T_MSGQ(0x01, printf("F%d", dballoc-=(mp->msg_ts + sizeof(struct msg)))); ! 316: } ! 317: ! 318: /* ! 319: * Send a Message ! 320: */ ! 321: umsgsnd(qid, bufp, msgsz, msgflg) ! 322: int qid; /* queue id */ ! 323: struct msgbuf *bufp; /* message buffer */ ! 324: int msgsz, /* message size */ ! 325: msgflg; /* flags */ ! 326: { ! 327: register struct msqid_ds *qp; /* message queue */ ! 328: register struct msg *mp, /* message struct */ ! 329: *tmp; ! 330: int q_num; /* number of a queue */ ! 331: int i_spot; /* # of empty entry in map */ ! 332: ! 333: /* Validate queue identifier. */ ! 334: for (qp = msqs; qp < msqs + NMSQID; qp++) ! 335: if (qp->msg_perm.seq == qid) /* found */ ! 336: break; ! 337: ! 338: q_num = qp - msqs; ! 339: /* qid is not a valid qid identifier */ ! 340: if (q_num >= NMSQID) { ! 341: u.u_error = EINVAL; ! 342: return -1; ! 343: } ! 344: ! 345: if (!(ipcaccess(&qp->msg_perm) & MSG_W)) { /* can't send mesg */ ! 346: u.u_error = EACCES; ! 347: return -1; ! 348: } ! 349: ! 350: /* Check if message has a valid message type and size. ! 351: * The comparisson with NMSQB was done because user could ! 352: * reduce this value. ! 353: */ ! 354: if (bufp->mtype < 1 || msgsz < 0 || msgsz > NMSC || msgsz > NMSQB) { ! 355: u.u_error = EACCES; ! 356: return -1; ! 357: } ! 358: ! 359: /* Now we have a valid message. Check if we can send it. */ ! 360: lock(msg_gate[q_num]); /* Lock it to avoid race condition */ ! 361: while (qp->msg_qnum >= NMSG || ! 362: qp->msg_qbytes < (qp->msg_cbytes + msgsz)) { ! 363: if (msgflg & IPC_NOWAIT) { ! 364: u.u_error = EAGAIN; ! 365: unlock(msg_gate[q_num]); ! 366: return -1; ! 367: } ! 368: /* We have to wait here */ ! 369: qp->msg_perm.mode |= MSG_WWAIT; ! 370: unlock(msg_gate[q_num]); ! 371: ! 372: if (x_sleep (qp, pritty, slpriSigCatch, "umsgsnd") ! 373: == PROCESS_SIGNALLED) { ! 374: /* Abort if a signal was received */ ! 375: u.u_error = EINTR; ! 376: return -1; ! 377: } ! 378: ! 379: /* Abort if the message queue was removed. */ ! 380: if (qid != qp->msg_perm.seq) { ! 381: u.u_error = EINVAL; ! 382: return -1; ! 383: } ! 384: lock(msg_gate[q_num]); ! 385: } ! 386: ! 387: /* Find empty entry in message map */ ! 388: for (i_spot = 0; i_spot < NMSQID * NMSG; i_spot++) ! 389: if (msg_map[i_spot] == NULL) ! 390: break; ! 391: /* It cannot happen when we do not have empty entry in map, ! 392: * but let check it. ! 393: */ ! 394: if (i_spot >= NMSQID * NMSG) { ! 395: u.u_error = ENOSPC; ! 396: return -1; ! 397: } ! 398: ! 399: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(struct msg))); ! 400: ! 401: /* Get space for the message header */ ! 402: if ((mp = kalloc(sizeof(struct msg))) == NULL) { ! 403: unlock(msg_gate[q_num]); ! 404: u.u_error = ENOSPC; ! 405: return -1; ! 406: } ! 407: ! 408: T_MSGQ(0x01, printf("A%d", dballoc += msgsz)); ! 409: ! 410: /* Alloc space for the message text */ ! 411: if ((msg_map[i_spot] = kalloc(msgsz)) == NULL) { ! 412: kfree(mp); ! 413: unlock(msg_gate[q_num]); ! 414: u.u_error = ENOSPC; ! 415: return -1; ! 416: } ! 417: ! 418: mp->msg_next = NULL; ! 419: mp->msg_ts = msgsz; ! 420: /* The map address is a number of msg_map array element */ ! 421: mp->msg_spot = i_spot; ! 422: ! 423: /* Transfer the message type and text.*/ ! 424: if (ukcopy(&(bufp->mtype), &(mp->msg_type), sizeof(mp->msg_type)) != ! 425: sizeof(mp->msg_type)) ! 426: u.u_error = EFAULT; ! 427: if (ukcopy(&bufp->mtext[0], msg_map[i_spot], msgsz) != msgsz) ! 428: u.u_error = EFAULT; ! 429: if (u.u_error) { ! 430: msgfree(mp); ! 431: unlock(msg_gate[q_num]); ! 432: return -1; ! 433: } ! 434: ! 435: /* Move the message to the desired queue. */ ! 436: if (qp->msg_first == NULL) /* This is the first message per queue */ ! 437: qp->msg_first = qp->msg_last = mp; ! 438: else { /* There are messages */ ! 439: /* Find last message in gueue */ ! 440: for (tmp = qp->msg_first; ; tmp = tmp->msg_next) ! 441: if (tmp->msg_next == NULL) ! 442: break; ! 443: qp->msg_last = tmp->msg_next = mp; ! 444: } ! 445: mp->msg_next = NULL; ! 446: ! 447: /* Update queue statistics. */ ! 448: qp->msg_cbytes += msgsz; ! 449: qp->msg_qnum++; ! 450: qp->msg_lspid = SELF->p_pid; ! 451: qp->msg_stime = timer.t_time; ! 452: ! 453: /* Unlock queue and wake processes waiting to receive. */ ! 454: unlock(msg_gate[q_num]); ! 455: if (qp->msg_perm.mode & MSG_RWAIT) { ! 456: qp->msg_perm.mode &= ~MSG_RWAIT; ! 457: wakeup(qp); ! 458: } ! 459: return 0; ! 460: } ! 461: ! 462: /* ! 463: * Receive a Message ! 464: */ ! 465: umsgrcv(qid, bufp, msgsz, msgtyp, msgflg) ! 466: int qid; /* Message queue id */ ! 467: struct msgbuf *bufp; /* Message buffer */ ! 468: int msgsz; /* Message text size */ ! 469: long msgtyp; /* Message type */ ! 470: int msgflg; /* Message flag */ ! 471: { ! 472: register struct msqid_ds *qp; /* queue headers */ ! 473: register struct msg *mp, /* message headers */ ! 474: *prev; ! 475: int q_num; /* queue number */ ! 476: int i_spot; ! 477: ! 478: /* Validate queue identifier. */ ! 479: if (qid < 0 || msqs == NULL) { ! 480: u.u_error = EINVAL; ! 481: return -1; ! 482: } ! 483: q_num = qid % NMSQID; ! 484: qp = &msqs[q_num]; ! 485: ! 486: /* Validate queue existence.*/ ! 487: if (qp->msg_perm.seq != qid || (qp->msg_perm.mode & IPC_ALLOC) == 0) { ! 488: u.u_error = EINVAL; ! 489: return -1; ! 490: } ! 491: ! 492: /* Permission denied */ ! 493: if ((ipcaccess(&qp->msg_perm) & MSG_R) == 0) { ! 494: u.u_error = EACCES; ! 495: return -1; ! 496: } ! 497: ! 498: /* Wait for message */ ! 499: lock(msg_gate[q_num]); ! 500: for (;;) { ! 501: prev = NULL; ! 502: mp = qp->msg_first; ! 503: /* Find mesg of type <= abs(msgtyp) */ ! 504: if (msgtyp < 0) { ! 505: struct msg *qmin; /* Message with lowest mtype */ ! 506: struct msg *xprev; /* Previous message */ ! 507: ! 508: qmin = NULL; ! 509: xprev = prev; ! 510: msgtyp = -msgtyp; ! 511: ! 512: for (; mp != NULL; prev = mp, mp = mp->msg_next) { ! 513: if (mp->msg_type > msgtyp) ! 514: continue; ! 515: if (qmin == NULL ! 516: || mp->msg_type < qmin->msg_type) { ! 517: xprev = prev; ! 518: qmin = mp; ! 519: } ! 520: } ! 521: prev = xprev; ! 522: mp = qmin; ! 523: msgtyp = -msgtyp; ! 524: } else if (msgtyp > 0) { /* Find message of type == msgtyp */ ! 525: while (mp != NULL && mp->msg_type != msgtyp) { ! 526: prev = mp; ! 527: mp = mp->msg_next; ! 528: } ! 529: } else /* Else take first message */ ! 530: mp = qp->msg_first; ! 531: ! 532: if (mp != NULL) /* Found */ ! 533: break; ! 534: ! 535: /* Can't wait to receive mesg */ ! 536: if (msgflg & IPC_NOWAIT) { ! 537: u.u_error = ENOMSG; ! 538: unlock(msg_gate[q_num]); ! 539: return -1; ! 540: } ! 541: ! 542: /* We can go sleep now */ ! 543: qp->msg_perm.mode |= MSG_RWAIT; ! 544: unlock(msg_gate[q_num]); ! 545: if (x_sleep (qp, pritty, slpriSigCatch, "umsgrcv") ! 546: == PROCESS_SIGNALLED) { ! 547: u.u_error = EINTR; ! 548: return -1; ! 549: } ! 550: ! 551: /* Not same q anymore */ ! 552: if (qid != qp->msg_perm.seq) { ! 553: u.u_error = EINVAL; ! 554: return -1; ! 555: } ! 556: lock(msg_gate[q_num]); ! 557: } ! 558: ! 559: /* Ensure entire message can be transferred, or MSG_NOERROR asserted.*/ ! 560: if (msgsz < mp->msg_ts && (msgflg & MSG_NOERROR) == 0) { ! 561: unlock(msg_gate[q_num]); ! 562: u.u_error = E2BIG; ! 563: return -1; ! 564: } ! 565: ! 566: /* Transfer message data */ ! 567: if (msgsz > mp->msg_ts) ! 568: msgsz = mp->msg_ts; ! 569: ! 570: kucopy(&(mp->msg_type), &(bufp->mtype), sizeof(mp->msg_type)); ! 571: ! 572: i_spot = mp->msg_spot; ! 573: if (kucopy(msg_map[i_spot], bufp->mtext, msgsz) != msgsz) ! 574: u.u_error = EFAULT; ! 575: ! 576: /* Abort if address fault occurred during transfer. */ ! 577: if (u.u_error) { ! 578: unlock(msg_gate[q_num]); ! 579: return -1; ! 580: } ! 581: /* Remove message from queue */ ! 582: if (prev != NULL) ! 583: prev->msg_next = mp->msg_next; ! 584: else ! 585: qp->msg_first = mp->msg_next; ! 586: ! 587: if (qp->msg_last == mp) ! 588: qp->msg_last = prev; ! 589: ! 590: ! 591: /* Update queue statistics */ ! 592: qp->msg_cbytes -= mp->msg_ts; ! 593: qp->msg_qnum--; ! 594: qp->msg_lrpid = SELF->p_pid; ! 595: qp->msg_rtime = timer.t_time; ! 596: ! 597: /* free message */ ! 598: msgfree(mp); ! 599: ! 600: unlock(msg_gate[q_num]); ! 601: /* Wakeup processes waiting to send. */ ! 602: if (qp->msg_perm.mode & MSG_WWAIT) { ! 603: qp->msg_perm.mode &= ~MSG_WWAIT; ! 604: wakeup(qp); ! 605: } ! 606: return msgsz; ! 607: } ! 608:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.