Annotation of XNU/bsd/kern/sysv_msg.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.