Annotation of XNU/bsd/kern/sysv_msg.c, revision 1.1.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.