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/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 /*      $OpenBSD: sysv_msg.c,v 1.40 2022/09/16 15:57:23 mbuhl Exp $     */
    2 /*      $NetBSD: sysv_msg.c,v 1.19 1996/02/09 19:00:18 christos Exp $   */
    3 /*
    4  * Copyright (c) 2009 Bret S. Lambert <blambert@openbsd.org>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 /*
   19  * Implementation of SVID messages
   20  *
   21  * Author:  Daniel Boulet
   22  *
   23  * Copyright 1993 Daniel Boulet and RTMX Inc.
   24  *
   25  * This system call was implemented by Daniel Boulet under contract from RTMX.
   26  *
   27  * Redistribution and use in source forms, with and without modification,
   28  * are permitted provided that this entire comment appears intact.
   29  *
   30  * Redistribution in binary form may occur without any restrictions.
   31  * Obviously, it would be nice if you gave credit where credit is due
   32  * but requiring it would be too onerous.
   33  *
   34  * This software is provided ``AS IS'' without any warranties of any kind.
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/mount.h>
   41 #include <sys/msg.h>
   42 #include <sys/pool.h>
   43 #include <sys/proc.h>
   44 #include <sys/queue.h>
   45 #include <sys/syscallargs.h>
   46 #include <sys/sysctl.h>
   47 #include <sys/systm.h>
   48 
   49 struct que *que_create(key_t, struct ucred *, int);
   50 struct que *que_lookup(int);
   51 struct que *que_key_lookup(key_t);
   52 void que_wakewriters(void);
   53 void que_free(struct que *);
   54 struct msg *msg_create(struct que *);
   55 void msg_free(struct msg *);
   56 void msg_enqueue(struct que *, struct msg *, struct proc *);
   57 void msg_dequeue(struct que *, struct msg *, struct proc *);
   58 struct msg *msg_lookup(struct que *, int);
   59 int msg_copyin(struct msg *, const char *, size_t, struct proc *);
   60 int msg_copyout(struct msg *, char *, size_t *, struct proc *);
   61 
   62 struct  pool sysvmsgpl;
   63 struct  msginfo msginfo;
   64 
   65 TAILQ_HEAD(, que) msg_queues;
   66 
   67 int num_ques;
   68 int num_msgs;
   69 int sequence;
   70 int maxmsgs;
   71 
   72 void
   73 msginit(void)
   74 {
   75         msginfo.msgmax = MSGMAX;
   76         msginfo.msgmni = MSGMNI;
   77         msginfo.msgmnb = MSGMNB;
   78         msginfo.msgtql = MSGTQL;
   79         msginfo.msgssz = MSGSSZ;
   80         msginfo.msgseg = MSGSEG;
   81 
   82         pool_init(&sysvmsgpl, sizeof(struct msg), 0, IPL_NONE, PR_WAITOK,
   83             "sysvmsgpl", NULL);
   84 
   85         TAILQ_INIT(&msg_queues);
   86 
   87         num_ques = 0;
   88         num_msgs = 0;
   89         sequence = 1;
   90         maxmsgs = 0;
   91 }
   92 
   93 int
   94 sys_msgctl(struct proc *p, void *v, register_t *retval)
   95 {
   96         struct sys_msgctl_args /* {
   97                 syscallarg(int) msqid;
   98                 syscallarg(int) cmd;
   99                 syscallarg(struct msqid_ds *) buf;
  100         } */ *uap = v;
  101         struct msqid_ds tmp, *umsq = SCARG(uap, buf);
  102         struct ucred *cred = p->p_ucred;
  103         struct que *que;
  104         int msqid = SCARG(uap, msqid);
  105         int cmd = SCARG(uap, cmd);
  106         int error;
  107 
  108         if ((que = que_lookup(msqid)) == NULL)
  109                 return (EINVAL);
  110 
  111         QREF(que);
  112 
  113         switch (cmd) {
  114 
  115         case IPC_RMID:
  116                 if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_M)))
  117                         goto out;
  118 
  119                 TAILQ_REMOVE(&msg_queues, que, que_next);
  120                 que->que_flags |= MSGQ_DYING;
  121 
  122                 /* lose interest in the queue and wait for others to too */
  123                 if (--que->que_references > 0) {
  124                         wakeup(que);
  125                         tsleep_nsec(&que->que_references, PZERO, "msgqrm",
  126                             INFSLP);
  127                 }
  128 
  129                 que_free(que);
  130 
  131                 return (0);
  132 
  133         case IPC_SET:
  134                 if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_M)))
  135                         goto out;
  136                 if ((error = copyin(umsq, &tmp, sizeof(struct msqid_ds))))
  137                         goto out;
  138 
  139                 /* only superuser can bump max bytes in queue */
  140                 if (tmp.msg_qbytes > que->msqid_ds.msg_qbytes &&
  141                     cred->cr_uid != 0) {
  142                         error = EPERM;
  143                         goto out;
  144                 }
  145 
  146                 /* restrict max bytes in queue to system limit */
  147                 if (tmp.msg_qbytes > msginfo.msgmnb)
  148                         tmp.msg_qbytes = msginfo.msgmnb;
  149 
  150                 /* can't reduce msg_bytes to 0 */
  151                 if (tmp.msg_qbytes == 0) {
  152                         error = EINVAL;         /* non-standard errno! */
  153                         goto out;
  154                 }
  155 
  156                 que->msqid_ds.msg_perm.uid = tmp.msg_perm.uid;
  157                 que->msqid_ds.msg_perm.gid = tmp.msg_perm.gid;
  158                 que->msqid_ds.msg_perm.mode =
  159                     (que->msqid_ds.msg_perm.mode & ~0777) |
  160                     (tmp.msg_perm.mode & 0777);
  161                 que->msqid_ds.msg_qbytes = tmp.msg_qbytes;
  162                 que->msqid_ds.msg_ctime = gettime();
  163                 break;
  164 
  165         case IPC_STAT:
  166                 if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_R)))
  167                         goto out;
  168                 error = copyout(&que->msqid_ds, umsq, sizeof(struct msqid_ds));
  169                 break;
  170 
  171         default:
  172                 error = EINVAL;
  173                 break;
  174         }
  175 out:
  176         QRELE(que);
  177 
  178         return (error);
  179 }
  180 
  181 int
  182 sys_msgget(struct proc *p, void *v, register_t *retval)
  183 {
  184         struct sys_msgget_args /* {
  185                 syscallarg(key_t) key;
  186                 syscallarg(int) msgflg;
  187         } */ *uap = v;
  188         struct ucred *cred = p->p_ucred;
  189         struct que *que;
  190         key_t key = SCARG(uap, key);
  191         int msgflg = SCARG(uap, msgflg);
  192         int error = 0;
  193 
  194 again:
  195         if (key != IPC_PRIVATE) {
  196                 que = que_key_lookup(key);
  197                 if (que) {
  198                         if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL))
  199                                 return (EEXIST);
  200                         if ((error = ipcperm(cred, &que->msqid_ds.msg_perm,
  201                             msgflg & 0700)))
  202                                 return (error);
  203                         goto found;
  204                 }
  205         }
  206 
  207         /* don't create a new message queue if the caller doesn't want to */
  208         if (key != IPC_PRIVATE && !(msgflg & IPC_CREAT))
  209                 return (ENOENT);
  210 
  211         /* enforce limits on the maximum number of message queues */
  212         if (num_ques >= msginfo.msgmni)
  213                 return (ENOSPC);
  214 
  215         /*
  216          * if que_create returns NULL, it means that a que with an identical
  217          * key was created while this process was sleeping, so start over
  218          */
  219         if ((que = que_create(key, cred, msgflg & 0777)) == NULL)
  220                 goto again;
  221 
  222 found:
  223         *retval = IXSEQ_TO_IPCID(que->que_ix, que->msqid_ds.msg_perm);
  224         return (error);
  225 }
  226 
  227 #define MSGQ_SPACE(q)   ((q)->msqid_ds.msg_qbytes - (q)->msqid_ds.msg_cbytes)
  228 
  229 int
  230 sys_msgsnd(struct proc *p, void *v, register_t *retval)
  231 {
  232         struct sys_msgsnd_args /* {
  233                 syscallarg(int) msqid;
  234                 syscallarg(const void *) msgp;
  235                 syscallarg(size_t) msgsz;
  236                 syscallarg(int) msgflg;
  237         } */ *uap = v;
  238         struct ucred *cred = p->p_ucred;
  239         struct que *que;
  240         struct msg *msg;
  241         size_t msgsz = SCARG(uap, msgsz);
  242         int error;
  243 
  244         if ((que = que_lookup(SCARG(uap, msqid))) == NULL)
  245                 return (EINVAL);
  246 
  247         if (msgsz > que->msqid_ds.msg_qbytes || msgsz > msginfo.msgmax)
  248                 return (EINVAL);
  249 
  250         if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_W)))
  251                 return (error);
  252 
  253         QREF(que);
  254 
  255         while (MSGQ_SPACE(que) < msgsz || num_msgs >= msginfo.msgtql) {
  256 
  257                 if (SCARG(uap, msgflg) & IPC_NOWAIT) {
  258                         error = EAGAIN;
  259                         goto out;
  260                 }
  261 
  262                 /* notify world that process may wedge here */
  263                 if (num_msgs >= msginfo.msgtql)
  264                         maxmsgs = 1;
  265 
  266                 que->que_flags |= MSGQ_WRITERS;
  267                 if ((error = tsleep_nsec(que, PZERO|PCATCH, "msgwait", INFSLP)))
  268                         goto out;
  269 
  270                 if (que->que_flags & MSGQ_DYING) {
  271                         error = EIDRM;
  272                         goto out;
  273                 }
  274         }
  275 
  276         /* if msg_create returns NULL, the queue is being removed */
  277         if ((msg = msg_create(que)) == NULL) {
  278                 error = EIDRM;
  279                 goto out;
  280         }
  281 
  282         /* msg_copyin frees msg on error */
  283         if ((error = msg_copyin(msg, (const char *)SCARG(uap, msgp), msgsz, p)))
  284                 goto out;
  285 
  286         msg_enqueue(que, msg, p);
  287 
  288         if (que->que_flags & MSGQ_READERS) {
  289                 que->que_flags &= ~MSGQ_READERS;
  290                 wakeup(que);
  291         }
  292 
  293         if (que->que_flags & MSGQ_DYING) {
  294                 error = EIDRM;
  295                 wakeup(que);
  296         }
  297 out:
  298         QRELE(que);
  299 
  300         return (error);
  301 }
  302 
  303 int
  304 sys_msgrcv(struct proc *p, void *v, register_t *retval)
  305 {
  306         struct sys_msgrcv_args /* {
  307                 syscallarg(int) msqid;
  308                 syscallarg(void *) msgp;
  309                 syscallarg(size_t) msgsz;
  310                 syscallarg(long) msgtyp;
  311                 syscallarg(int) msgflg;
  312         } */ *uap = v;
  313         struct ucred *cred = p->p_ucred;
  314         char *msgp = SCARG(uap, msgp);
  315         struct que *que;
  316         struct msg *msg;
  317         size_t msgsz = SCARG(uap, msgsz);
  318         long msgtyp = SCARG(uap, msgtyp);
  319         int error;
  320 
  321         if ((que = que_lookup(SCARG(uap, msqid))) == NULL)
  322                 return (EINVAL);
  323 
  324         if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_R)))
  325                 return (error);
  326 
  327         QREF(que);
  328 
  329         /* msg_lookup handles matching; sleeping gets handled here */
  330         while ((msg = msg_lookup(que, msgtyp)) == NULL) {
  331 
  332                 if (SCARG(uap, msgflg) & IPC_NOWAIT) {
  333                         error = ENOMSG;
  334                         goto out;
  335                 }
  336 
  337                 que->que_flags |= MSGQ_READERS;
  338                 if ((error = tsleep_nsec(que, PZERO|PCATCH, "msgwait", INFSLP)))
  339                         goto out;
  340 
  341                 /* make sure the queue still alive */
  342                 if (que->que_flags & MSGQ_DYING) {
  343                         error = EIDRM;
  344                         goto out;
  345                 }
  346         }
  347 
  348         /* if msg_copyout fails, keep the message around so it isn't lost */
  349         if ((error = msg_copyout(msg, msgp, &msgsz, p)))
  350                 goto out;
  351 
  352         msg_dequeue(que, msg, p);
  353         msg_free(msg);
  354 
  355         if (que->que_flags & MSGQ_WRITERS) {
  356                 que->que_flags &= ~MSGQ_WRITERS;
  357                 wakeup(que);
  358         }
  359 
  360         /* ensure processes waiting on the global limit don't wedge */
  361         if (maxmsgs) {
  362                 maxmsgs = 0;
  363                 que_wakewriters();
  364         }
  365 
  366         *retval = msgsz;
  367 out:
  368         QRELE(que);
  369 
  370         return (error);
  371 }
  372 
  373 /*
  374  * que management functions
  375  */
  376 
  377 struct que *
  378 que_create(key_t key, struct ucred *cred, int mode)
  379 {
  380         struct que *que, *que2;
  381         int nextix = 1;
  382 
  383         que = malloc(sizeof(*que), M_TEMP, M_WAIT|M_ZERO);
  384 
  385         /* if malloc slept, a queue with the same key may have been created */
  386         if (que_key_lookup(key)) {
  387                 free(que, M_TEMP, sizeof *que);
  388                 return (NULL);
  389         }
  390 
  391         /* find next available "index" */
  392         TAILQ_FOREACH(que2, &msg_queues, que_next) {
  393                 if (nextix < que2->que_ix)
  394                         break;
  395                 nextix = que2->que_ix + 1;
  396         }
  397         que->que_ix = nextix;
  398 
  399         que->msqid_ds.msg_perm.key = key;
  400         que->msqid_ds.msg_perm.cuid = cred->cr_uid;
  401         que->msqid_ds.msg_perm.uid = cred->cr_uid;
  402         que->msqid_ds.msg_perm.cgid = cred->cr_gid;
  403         que->msqid_ds.msg_perm.gid = cred->cr_gid;
  404         que->msqid_ds.msg_perm.mode = mode & 0777;
  405         que->msqid_ds.msg_perm.seq = ++sequence & 0x7fff;
  406         que->msqid_ds.msg_qbytes = msginfo.msgmnb;
  407         que->msqid_ds.msg_ctime = gettime();
  408 
  409         TAILQ_INIT(&que->que_msgs);
  410 
  411         /* keep queues in "index" order */
  412         if (que2)
  413                 TAILQ_INSERT_BEFORE(que2, que, que_next);
  414         else
  415                 TAILQ_INSERT_TAIL(&msg_queues, que, que_next);
  416         num_ques++;
  417 
  418         return (que);
  419 }
  420 
  421 struct que *
  422 que_lookup(int id)
  423 {
  424         struct que *que;
  425 
  426         TAILQ_FOREACH(que, &msg_queues, que_next)
  427                 if (que->que_ix == IPCID_TO_IX(id))
  428                         break;
  429 
  430         /* don't return queues marked for removal */
  431         if (que && que->que_flags & MSGQ_DYING)
  432                 return (NULL);
  433 
  434         return (que);
  435 }
  436 
  437 struct que *
  438 que_key_lookup(key_t key)
  439 {
  440         struct que *que;
  441 
  442         if (key == IPC_PRIVATE)
  443                 return (NULL);
  444 
  445         TAILQ_FOREACH(que, &msg_queues, que_next)
  446                 if (que->msqid_ds.msg_perm.key == key)
  447                         break;
  448 
  449         /* don't return queues marked for removal */
  450         if (que && que->que_flags & MSGQ_DYING)
  451                 return (NULL);
  452 
  453         return (que);
  454 }
  455 
  456 void
  457 que_wakewriters(void)
  458 {
  459         struct que *que;
  460 
  461         TAILQ_FOREACH(que, &msg_queues, que_next) {
  462                 if (que->que_flags & MSGQ_WRITERS) {
  463                         que->que_flags &= ~MSGQ_WRITERS;
  464                         wakeup(que);
  465                 }
  466         }
  467 }
  468 
  469 void
  470 que_free(struct que *que)
  471 {
  472         struct msg *msg;
  473 #ifdef DIAGNOSTIC
  474         if (que->que_references > 0)
  475                 panic("freeing message queue with active references");
  476 #endif
  477 
  478         while ((msg = TAILQ_FIRST(&que->que_msgs))) {
  479                 TAILQ_REMOVE(&que->que_msgs, msg, msg_next);
  480                 msg_free(msg);
  481         }
  482         free(que, M_TEMP, sizeof *que);
  483         num_ques--;
  484 }
  485 
  486 /*
  487  * msg management functions
  488  */
  489 
  490 struct msg *
  491 msg_create(struct que *que)
  492 {
  493         struct msg *msg;
  494 
  495         msg = pool_get(&sysvmsgpl, PR_WAITOK|PR_ZERO);
  496 
  497         /* if the queue has died during allocation, return NULL */
  498         if (que->que_flags & MSGQ_DYING) {
  499                 pool_put(&sysvmsgpl, msg);
  500                 wakeup(que);
  501                 return(NULL);
  502         }
  503 
  504         num_msgs++;
  505 
  506         return (msg);
  507 }
  508 
  509 struct msg *
  510 msg_lookup(struct que *que, int msgtyp)
  511 {
  512         struct msg *msg;
  513 
  514         /*
  515          * Three different matches are performed based on the value of msgtyp:
  516          * 1) msgtyp > 0 => match exactly
  517          * 2) msgtyp = 0 => match any
  518          * 3) msgtyp < 0 => match any up to absolute value of msgtyp
  519          */
  520         TAILQ_FOREACH(msg, &que->que_msgs, msg_next)
  521                 if (msgtyp == 0 || msgtyp == msg->msg_type ||
  522                     (msgtyp < 0 && -msgtyp <= msg->msg_type))
  523                         break;
  524 
  525         return (msg);
  526 }
  527 
  528 void
  529 msg_free(struct msg *msg)
  530 {
  531         m_freem(msg->msg_data);
  532         pool_put(&sysvmsgpl, msg);
  533         num_msgs--;
  534 }
  535 
  536 void
  537 msg_enqueue(struct que *que, struct msg *msg, struct proc *p)
  538 {
  539         que->msqid_ds.msg_cbytes += msg->msg_len;
  540         que->msqid_ds.msg_qnum++;
  541         que->msqid_ds.msg_lspid = p->p_p->ps_pid;
  542         que->msqid_ds.msg_stime = gettime();
  543 
  544         TAILQ_INSERT_TAIL(&que->que_msgs, msg, msg_next);
  545 }
  546 
  547 void
  548 msg_dequeue(struct que *que, struct msg *msg, struct proc *p)
  549 {
  550         que->msqid_ds.msg_cbytes -= msg->msg_len;
  551         que->msqid_ds.msg_qnum--;
  552         que->msqid_ds.msg_lrpid = p->p_p->ps_pid;
  553         que->msqid_ds.msg_rtime = gettime();
  554 
  555         TAILQ_REMOVE(&que->que_msgs, msg, msg_next);
  556 }
  557 
  558 /*
  559  * The actual I/O routines. A note concerning the layout of SysV msg buffers:
  560  *
  561  * The data to be copied is laid out as a single userspace buffer, with a
  562  * long preceding an opaque buffer of len bytes. The long value ends
  563  * up being the message type, which needs to be copied separately from
  564  * the buffer data, which is stored in in mbufs.
  565  */
  566 
  567 int
  568 msg_copyin(struct msg *msg, const char *ubuf, size_t len, struct proc *p)
  569 {
  570         struct mbuf **mm, *m;
  571         size_t xfer;
  572         int error;
  573 
  574         if (msg == NULL)
  575                 panic ("msg NULL");
  576 
  577         if ((error = copyin(ubuf, &msg->msg_type, sizeof(long)))) {
  578                 msg_free(msg);
  579                 return (error);
  580         }
  581 
  582         if (msg->msg_type < 1) {
  583                 msg_free(msg);
  584                 return (EINVAL);
  585         }
  586 
  587         ubuf += sizeof(long);
  588 
  589         msg->msg_len = 0;
  590         mm = &msg->msg_data;
  591 
  592         while (msg->msg_len < len) {
  593                 m = m_get(M_WAIT, MT_DATA);
  594                 if (len >= MINCLSIZE) {
  595                         MCLGET(m, M_WAIT);
  596                         xfer = min(len, MCLBYTES);
  597                 } else {
  598                         xfer = min(len, MLEN);
  599                 }
  600                 m->m_len = xfer;
  601                 msg->msg_len += xfer;
  602                 *mm = m;
  603                 mm = &m->m_next;
  604         }
  605 
  606         for (m = msg->msg_data; m; m = m->m_next) {
  607                 if ((error = copyin(ubuf, mtod(m, void *), m->m_len))) {
  608                         msg_free(msg);
  609                         return (error);
  610                 }
  611                 ubuf += m->m_len;
  612         }
  613 
  614         return (0);
  615 }
  616 
  617 int
  618 msg_copyout(struct msg *msg, char *ubuf, size_t *len, struct proc *p)
  619 {
  620         struct mbuf *m;
  621         size_t xfer;
  622         int error;
  623 
  624 #ifdef DIAGNOSTIC
  625         if (msg->msg_len > MSGMAX)
  626                 panic("SysV message longer than MSGMAX");
  627 #endif
  628 
  629         /* silently truncate messages too large for user buffer */
  630         xfer = min(*len, msg->msg_len);
  631 
  632         if ((error = copyout(&msg->msg_type, ubuf, sizeof(long))))
  633                 return (error);
  634 
  635         ubuf += sizeof(long);
  636         *len = xfer;
  637 
  638         for (m = msg->msg_data; m; m = m->m_next) {
  639                 if ((error = copyout(mtod(m, void *), ubuf, m->m_len)))
  640                         return (error);
  641                 ubuf += m->m_len;
  642         }
  643 
  644         return (0);
  645 }
  646 
  647 int
  648 sysctl_sysvmsg(int *name, u_int namelen, void *where, size_t *sizep)
  649 {
  650         struct msg_sysctl_info *info;
  651         struct que *que;
  652         size_t infolen, infolen0;
  653         int error;
  654 
  655         switch (*name) {
  656         case KERN_SYSVIPC_MSG_INFO:
  657 
  658                 if (namelen != 1)
  659                         return (ENOTDIR);
  660 
  661                 /*
  662                  * The userland ipcs(1) utility expects to be able
  663                  * to iterate over at least msginfo.msgmni queues,
  664                  * even if those queues don't exist. This is an
  665                  * artifact of the previous implementation of
  666                  * message queues; for now, emulate this behavior
  667                  * until a more thorough fix can be made.
  668                  */
  669                 infolen0 = sizeof(msginfo) +
  670                     msginfo.msgmni * sizeof(struct msqid_ds);
  671                 if (where == NULL) {
  672                         *sizep = infolen0;
  673                         return (0);
  674                 }
  675 
  676                 /*
  677                  * More special-casing due to previous implementation:
  678                  * if the caller just wants the msginfo struct, then
  679                  * sizep will point to the value sizeof(struct msginfo).
  680                  * In that case, only copy out the msginfo struct to
  681                  * the caller.
  682                  */
  683                 if (*sizep == sizeof(struct msginfo))
  684                         return (copyout(&msginfo, where, sizeof(msginfo)));
  685 
  686                 info = malloc(infolen0, M_TEMP, M_WAIT|M_ZERO);
  687 
  688                 /* if the malloc slept, this may have changed */
  689                 infolen = sizeof(msginfo) +
  690                     msginfo.msgmni * sizeof(struct msqid_ds);
  691 
  692                 if (*sizep < infolen) {
  693                         free(info, M_TEMP, infolen0);
  694                         return (ENOMEM);
  695                 }
  696 
  697                 memcpy(&info->msginfo, &msginfo, sizeof(struct msginfo));
  698 
  699                 /*
  700                  * Special case #3: the previous array-based implementation
  701                  * exported the array indices and userland has come to rely
  702                  * upon these indices, so keep behavior consistent.
  703                  */
  704                 TAILQ_FOREACH(que, &msg_queues, que_next)
  705                         memcpy(&info->msgids[que->que_ix], &que->msqid_ds,
  706                             sizeof(struct msqid_ds));
  707 
  708                 error = copyout(info, where, infolen);
  709 
  710                 free(info, M_TEMP, infolen0);
  711 
  712                 return (error);
  713 
  714         default:
  715                 return (EINVAL);
  716         }
  717 }

Cache object: 1a2f8969c53ac62088b7858eda741a97


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