[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     ! 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