[BACK]Return to sysv_msg.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/sysv_msg.c, Revision 1.1.1.1

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

CVSweb