The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/kern/sysv_msg.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: f1da58e01944bce8f2d6753ced241964


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.