LCOV - code coverage report
Current view: top level - kern - uipc_usrreq.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 533 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: uipc_usrreq.c,v 1.134 2018/07/09 10:58:21 claudio Exp $       */
       2             : /*      $NetBSD: uipc_usrreq.c,v 1.18 1996/02/09 19:00:50 christos Exp $        */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1982, 1986, 1989, 1991, 1993
       6             :  *      The Regents of the University of California.  All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  * 3. Neither the name of the University nor the names of its contributors
      17             :  *    may be used to endorse or promote products derived from this software
      18             :  *    without specific prior written permission.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      21             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      22             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      23             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      24             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      25             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      26             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      27             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      28             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      29             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      30             :  * SUCH DAMAGE.
      31             :  *
      32             :  *      @(#)uipc_usrreq.c       8.3 (Berkeley) 1/4/94
      33             :  */
      34             : 
      35             : #include <sys/param.h>
      36             : #include <sys/systm.h>
      37             : #include <sys/proc.h>
      38             : #include <sys/filedesc.h>
      39             : #include <sys/domain.h>
      40             : #include <sys/protosw.h>
      41             : #include <sys/queue.h>
      42             : #include <sys/socket.h>
      43             : #include <sys/socketvar.h>
      44             : #include <sys/unpcb.h>
      45             : #include <sys/un.h>
      46             : #include <sys/namei.h>
      47             : #include <sys/vnode.h>
      48             : #include <sys/file.h>
      49             : #include <sys/stat.h>
      50             : #include <sys/mbuf.h>
      51             : #include <sys/task.h>
      52             : #include <sys/pledge.h>
      53             : 
      54             : void    uipc_setaddr(const struct unpcb *, struct mbuf *);
      55             : 
      56             : /* list of all UNIX domain sockets, for unp_gc() */
      57             : LIST_HEAD(unp_head, unpcb) unp_head = LIST_HEAD_INITIALIZER(unp_head);
      58             : 
      59             : /*
      60             :  * Stack of sets of files that were passed over a socket but were
      61             :  * not received and need to be closed.
      62             :  */
      63             : struct  unp_deferral {
      64             :         SLIST_ENTRY(unp_deferral)       ud_link;
      65             :         int     ud_n;
      66             :         /* followed by ud_n struct fdpass */
      67             :         struct fdpass ud_fp[];
      68             : };
      69             : 
      70             : void    unp_discard(struct fdpass *, int);
      71             : void    unp_mark(struct fdpass *, int);
      72             : void    unp_scan(struct mbuf *, void (*)(struct fdpass *, int));
      73             : int     unp_nam2sun(struct mbuf *, struct sockaddr_un **, size_t *);
      74             : 
      75             : /* list of sets of files that were sent over sockets that are now closed */
      76             : SLIST_HEAD(,unp_deferral) unp_deferred = SLIST_HEAD_INITIALIZER(unp_deferred);
      77             : 
      78             : struct task unp_gc_task = TASK_INITIALIZER(unp_gc, NULL);
      79             : 
      80             : 
      81             : /*
      82             :  * Unix communications domain.
      83             :  *
      84             :  * TODO:
      85             :  *      RDM
      86             :  *      rethink name space problems
      87             :  *      need a proper out-of-band
      88             :  */
      89             : struct  sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
      90             : ino_t   unp_ino;                        /* prototype for fake inode numbers */
      91             : 
      92             : void
      93           0 : uipc_setaddr(const struct unpcb *unp, struct mbuf *nam)
      94             : {
      95           0 :         if (unp != NULL && unp->unp_addr != NULL) {
      96           0 :                 nam->m_len = unp->unp_addr->m_len;
      97           0 :                 memcpy(mtod(nam, caddr_t), mtod(unp->unp_addr, caddr_t),
      98             :                     nam->m_len);
      99           0 :         } else {
     100           0 :                 nam->m_len = sizeof(sun_noname);
     101           0 :                 memcpy(mtod(nam, struct sockaddr *), &sun_noname,
     102             :                     nam->m_len);
     103             :         }
     104           0 : }
     105             : 
     106             : int
     107           0 : uipc_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
     108             :     struct mbuf *control, struct proc *p)
     109             : {
     110           0 :         struct unpcb *unp = sotounpcb(so);
     111             :         struct socket *so2;
     112             :         int error = 0;
     113             : 
     114           0 :         if (req == PRU_CONTROL)
     115           0 :                 return (EOPNOTSUPP);
     116           0 :         if (req != PRU_SEND && control && control->m_len) {
     117             :                 error = EOPNOTSUPP;
     118           0 :                 goto release;
     119             :         }
     120           0 :         if (unp == NULL) {
     121             :                 error = EINVAL;
     122           0 :                 goto release;
     123             :         }
     124             : 
     125           0 :         NET_ASSERT_UNLOCKED();
     126             : 
     127           0 :         switch (req) {
     128             : 
     129             :         case PRU_BIND:
     130           0 :                 error = unp_bind(unp, nam, p);
     131           0 :                 break;
     132             : 
     133             :         case PRU_LISTEN:
     134           0 :                 if (unp->unp_vnode == NULL)
     135           0 :                         error = EINVAL;
     136             :                 break;
     137             : 
     138             :         case PRU_CONNECT:
     139           0 :                 error = unp_connect(so, nam, p);
     140           0 :                 break;
     141             : 
     142             :         case PRU_CONNECT2:
     143           0 :                 error = unp_connect2(so, (struct socket *)nam);
     144           0 :                 break;
     145             : 
     146             :         case PRU_DISCONNECT:
     147           0 :                 unp_disconnect(unp);
     148           0 :                 break;
     149             : 
     150             :         case PRU_ACCEPT:
     151             :                 /*
     152             :                  * Pass back name of connected socket,
     153             :                  * if it was bound and we are still connected
     154             :                  * (our peer may have closed already!).
     155             :                  */
     156           0 :                 uipc_setaddr(unp->unp_conn, nam);
     157           0 :                 break;
     158             : 
     159             :         case PRU_SHUTDOWN:
     160           0 :                 socantsendmore(so);
     161           0 :                 unp_shutdown(unp);
     162           0 :                 break;
     163             : 
     164             :         case PRU_RCVD:
     165           0 :                 switch (so->so_type) {
     166             : 
     167             :                 case SOCK_DGRAM:
     168           0 :                         panic("uipc 1");
     169             :                         /*NOTREACHED*/
     170             : 
     171             :                 case SOCK_STREAM:
     172             :                 case SOCK_SEQPACKET:
     173           0 :                         if (unp->unp_conn == NULL)
     174             :                                 break;
     175           0 :                         so2 = unp->unp_conn->unp_socket;
     176             :                         /*
     177             :                          * Adjust backpressure on sender
     178             :                          * and wakeup any waiting to write.
     179             :                          */
     180           0 :                         so2->so_snd.sb_mbcnt = so->so_rcv.sb_mbcnt;
     181           0 :                         so2->so_snd.sb_cc = so->so_rcv.sb_cc;
     182           0 :                         sowwakeup(so2);
     183           0 :                         break;
     184             : 
     185             :                 default:
     186           0 :                         panic("uipc 2");
     187             :                 }
     188             :                 break;
     189             : 
     190             :         case PRU_SEND:
     191           0 :                 if (control && (error = unp_internalize(control, p)))
     192             :                         break;
     193           0 :                 switch (so->so_type) {
     194             : 
     195             :                 case SOCK_DGRAM: {
     196             :                         struct sockaddr *from;
     197             : 
     198           0 :                         if (nam) {
     199           0 :                                 if (unp->unp_conn) {
     200             :                                         error = EISCONN;
     201           0 :                                         break;
     202             :                                 }
     203           0 :                                 error = unp_connect(so, nam, p);
     204           0 :                                 if (error)
     205           0 :                                         break;
     206             :                         } else {
     207           0 :                                 if (unp->unp_conn == NULL) {
     208             :                                         error = ENOTCONN;
     209           0 :                                         break;
     210             :                                 }
     211             :                         }
     212           0 :                         so2 = unp->unp_conn->unp_socket;
     213           0 :                         if (unp->unp_addr)
     214           0 :                                 from = mtod(unp->unp_addr, struct sockaddr *);
     215             :                         else
     216             :                                 from = &sun_noname;
     217           0 :                         if (sbappendaddr(so2, &so2->so_rcv, from, m, control)) {
     218           0 :                                 sorwakeup(so2);
     219             :                                 m = NULL;
     220             :                                 control = NULL;
     221           0 :                         } else
     222             :                                 error = ENOBUFS;
     223           0 :                         if (nam)
     224           0 :                                 unp_disconnect(unp);
     225           0 :                         break;
     226             :                 }
     227             : 
     228             :                 case SOCK_STREAM:
     229             :                 case SOCK_SEQPACKET:
     230           0 :                         if (so->so_state & SS_CANTSENDMORE) {
     231             :                                 error = EPIPE;
     232           0 :                                 break;
     233             :                         }
     234           0 :                         if (unp->unp_conn == NULL) {
     235             :                                 error = ENOTCONN;
     236           0 :                                 break;
     237             :                         }
     238           0 :                         so2 = unp->unp_conn->unp_socket;
     239             :                         /*
     240             :                          * Send to paired receive port, and then raise
     241             :                          * send buffer counts to maintain backpressure.
     242             :                          * Wake up readers.
     243             :                          */
     244           0 :                         if (control) {
     245           0 :                                 if (sbappendcontrol(so2, &so2->so_rcv, m,
     246             :                                     control)) {
     247             :                                         control = NULL;
     248             :                                 } else {
     249             :                                         error = ENOBUFS;
     250           0 :                                         break;
     251             :                                 }
     252           0 :                         } else if (so->so_type == SOCK_SEQPACKET)
     253           0 :                                 sbappendrecord(so2, &so2->so_rcv, m);
     254             :                         else
     255           0 :                                 sbappend(so2, &so2->so_rcv, m);
     256           0 :                         so->so_snd.sb_mbcnt = so2->so_rcv.sb_mbcnt;
     257           0 :                         so->so_snd.sb_cc = so2->so_rcv.sb_cc;
     258           0 :                         sorwakeup(so2);
     259             :                         m = NULL;
     260           0 :                         break;
     261             : 
     262             :                 default:
     263           0 :                         panic("uipc 4");
     264             :                 }
     265             :                 /* we need to undo unp_internalize in case of errors */
     266           0 :                 if (control && error)
     267           0 :                         unp_dispose(control);
     268             :                 break;
     269             : 
     270             :         case PRU_ABORT:
     271           0 :                 unp_drop(unp, ECONNABORTED);
     272           0 :                 break;
     273             : 
     274             :         case PRU_SENSE: {
     275           0 :                 struct stat *sb = (struct stat *)m;
     276             : 
     277           0 :                 sb->st_blksize = so->so_snd.sb_hiwat;
     278           0 :                 sb->st_dev = NODEV;
     279           0 :                 if (unp->unp_ino == 0)
     280           0 :                         unp->unp_ino = unp_ino++;
     281           0 :                 sb->st_atim.tv_sec =
     282           0 :                     sb->st_mtim.tv_sec =
     283           0 :                     sb->st_ctim.tv_sec = unp->unp_ctime.tv_sec;
     284           0 :                 sb->st_atim.tv_nsec =
     285           0 :                     sb->st_mtim.tv_nsec =
     286           0 :                     sb->st_ctim.tv_nsec = unp->unp_ctime.tv_nsec;
     287           0 :                 sb->st_ino = unp->unp_ino;
     288             :                 return (0);
     289             :         }
     290             : 
     291             :         case PRU_RCVOOB:
     292           0 :                 return (EOPNOTSUPP);
     293             : 
     294             :         case PRU_SENDOOB:
     295             :                 error = EOPNOTSUPP;
     296           0 :                 break;
     297             : 
     298             :         case PRU_SOCKADDR:
     299           0 :                 uipc_setaddr(unp, nam);
     300           0 :                 break;
     301             : 
     302             :         case PRU_PEERADDR:
     303           0 :                 uipc_setaddr(unp->unp_conn, nam);
     304           0 :                 break;
     305             : 
     306             :         case PRU_SLOWTIMO:
     307             :                 break;
     308             : 
     309             :         default:
     310           0 :                 panic("uipc_usrreq");
     311             :         }
     312             : release:
     313           0 :         m_freem(control);
     314           0 :         m_freem(m);
     315           0 :         return (error);
     316           0 : }
     317             : 
     318             : /*
     319             :  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
     320             :  * for stream sockets, although the total for sender and receiver is
     321             :  * actually only PIPSIZ.
     322             :  * Datagram sockets really use the sendspace as the maximum datagram size,
     323             :  * and don't really want to reserve the sendspace.  Their recvspace should
     324             :  * be large enough for at least one max-size datagram plus address.
     325             :  */
     326             : #define PIPSIZ  4096
     327             : u_long  unpst_sendspace = PIPSIZ;
     328             : u_long  unpst_recvspace = PIPSIZ;
     329             : u_long  unpdg_sendspace = 2*1024;       /* really max datagram size */
     330             : u_long  unpdg_recvspace = 4*1024;
     331             : 
     332             : int     unp_rights;                     /* file descriptors in flight */
     333             : 
     334             : int
     335           0 : uipc_attach(struct socket *so, int proto)
     336             : {
     337             :         struct unpcb *unp;
     338             :         int error;
     339             :         
     340           0 :         if (so->so_pcb)
     341           0 :                 return EISCONN;
     342           0 :         if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
     343           0 :                 switch (so->so_type) {
     344             : 
     345             :                 case SOCK_STREAM:
     346             :                 case SOCK_SEQPACKET:
     347           0 :                         error = soreserve(so, unpst_sendspace, unpst_recvspace);
     348           0 :                         break;
     349             : 
     350             :                 case SOCK_DGRAM:
     351           0 :                         error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
     352           0 :                         break;
     353             : 
     354             :                 default:
     355           0 :                         panic("unp_attach");
     356             :                 }
     357           0 :                 if (error)
     358           0 :                         return (error);
     359             :         }
     360           0 :         unp = malloc(sizeof(*unp), M_PCB, M_NOWAIT|M_ZERO);
     361           0 :         if (unp == NULL)
     362           0 :                 return (ENOBUFS);
     363           0 :         unp->unp_socket = so;
     364           0 :         so->so_pcb = unp;
     365           0 :         getnanotime(&unp->unp_ctime);
     366           0 :         LIST_INSERT_HEAD(&unp_head, unp, unp_link);
     367           0 :         return (0);
     368           0 : }
     369             : 
     370             : int
     371           0 : uipc_detach(struct socket *so)
     372             : {
     373           0 :         struct unpcb *unp = sotounpcb(so);
     374             : 
     375           0 :         if (unp == NULL)
     376           0 :                 return (EINVAL);
     377             : 
     378           0 :         NET_ASSERT_UNLOCKED();
     379             : 
     380           0 :         unp_detach(unp);
     381             : 
     382           0 :         return (0);
     383           0 : }
     384             : 
     385             : void
     386           0 : unp_detach(struct unpcb *unp)
     387             : {
     388             :         struct vnode *vp;
     389             : 
     390           0 :         LIST_REMOVE(unp, unp_link);
     391           0 :         if (unp->unp_vnode) {
     392           0 :                 unp->unp_vnode->v_socket = NULL;
     393           0 :                 vp = unp->unp_vnode;
     394           0 :                 unp->unp_vnode = NULL;
     395           0 :                 vrele(vp);
     396           0 :         }
     397           0 :         if (unp->unp_conn)
     398           0 :                 unp_disconnect(unp);
     399           0 :         while (!SLIST_EMPTY(&unp->unp_refs))
     400           0 :                 unp_drop(SLIST_FIRST(&unp->unp_refs), ECONNRESET);
     401           0 :         soisdisconnected(unp->unp_socket);
     402           0 :         unp->unp_socket->so_pcb = NULL;
     403           0 :         m_freem(unp->unp_addr);
     404           0 :         free(unp, M_PCB, sizeof *unp);
     405           0 :         if (unp_rights)
     406           0 :                 task_add(systq, &unp_gc_task);
     407           0 : }
     408             : 
     409             : int
     410           0 : unp_bind(struct unpcb *unp, struct mbuf *nam, struct proc *p)
     411             : {
     412           0 :         struct sockaddr_un *soun;
     413             :         struct mbuf *nam2;
     414             :         struct vnode *vp;
     415           0 :         struct vattr vattr;
     416             :         int error;
     417           0 :         struct nameidata nd;
     418           0 :         size_t pathlen;
     419             : 
     420           0 :         if (unp->unp_vnode != NULL)
     421           0 :                 return (EINVAL);
     422           0 :         if ((error = unp_nam2sun(nam, &soun, &pathlen)))
     423           0 :                 return (error);
     424             : 
     425           0 :         nam2 = m_getclr(M_WAITOK, MT_SONAME);
     426           0 :         nam2->m_len = sizeof(struct sockaddr_un);
     427           0 :         memcpy(mtod(nam2, struct sockaddr_un *), soun,
     428             :             offsetof(struct sockaddr_un, sun_path) + pathlen);
     429             :         /* No need to NUL terminate: m_getclr() returns zero'd mbufs. */
     430             : 
     431           0 :         soun = mtod(nam2, struct sockaddr_un *);
     432             : 
     433             :         /* Fixup sun_len to keep it in sync with m_len. */
     434           0 :         soun->sun_len = nam2->m_len;
     435             : 
     436           0 :         NDINIT(&nd, CREATE, NOFOLLOW | LOCKPARENT, UIO_SYSSPACE,
     437             :             soun->sun_path, p);
     438           0 :         nd.ni_pledge = PLEDGE_UNIX;
     439             : /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
     440           0 :         if ((error = namei(&nd)) != 0) {
     441           0 :                 m_freem(nam2);
     442           0 :                 return (error);
     443             :         }
     444           0 :         vp = nd.ni_vp;
     445           0 :         if (vp != NULL) {
     446           0 :                 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
     447           0 :                 if (nd.ni_dvp == vp)
     448           0 :                         vrele(nd.ni_dvp);
     449             :                 else
     450           0 :                         vput(nd.ni_dvp);
     451           0 :                 vrele(vp);
     452           0 :                 m_freem(nam2);
     453           0 :                 return (EADDRINUSE);
     454             :         }
     455           0 :         VATTR_NULL(&vattr);
     456           0 :         vattr.va_type = VSOCK;
     457           0 :         vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
     458           0 :         error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
     459           0 :         vput(nd.ni_dvp);
     460           0 :         if (error) {
     461           0 :                 m_freem(nam2);
     462           0 :                 return (error);
     463             :         }
     464           0 :         unp->unp_addr = nam2;
     465           0 :         vp = nd.ni_vp;
     466           0 :         vp->v_socket = unp->unp_socket;
     467           0 :         unp->unp_vnode = vp;
     468           0 :         unp->unp_connid.uid = p->p_ucred->cr_uid;
     469           0 :         unp->unp_connid.gid = p->p_ucred->cr_gid;
     470           0 :         unp->unp_connid.pid = p->p_p->ps_pid;
     471           0 :         unp->unp_flags |= UNP_FEIDSBIND;
     472           0 :         VOP_UNLOCK(vp);
     473           0 :         return (0);
     474           0 : }
     475             : 
     476             : int
     477           0 : unp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
     478             : {
     479           0 :         struct sockaddr_un *soun;
     480             :         struct vnode *vp;
     481             :         struct socket *so2, *so3;
     482             :         struct unpcb *unp, *unp2, *unp3;
     483           0 :         struct nameidata nd;
     484             :         int error;
     485             : 
     486           0 :         if ((error = unp_nam2sun(nam, &soun, NULL)))
     487           0 :                 return (error);
     488             : 
     489           0 :         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p);
     490           0 :         nd.ni_pledge = PLEDGE_UNIX;
     491           0 :         if ((error = namei(&nd)) != 0)
     492           0 :                 return (error);
     493           0 :         vp = nd.ni_vp;
     494           0 :         if (vp->v_type != VSOCK) {
     495             :                 error = ENOTSOCK;
     496           0 :                 goto bad;
     497             :         }
     498           0 :         if ((error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) != 0)
     499             :                 goto bad;
     500           0 :         so2 = vp->v_socket;
     501           0 :         if (so2 == NULL) {
     502             :                 error = ECONNREFUSED;
     503           0 :                 goto bad;
     504             :         }
     505           0 :         if (so->so_type != so2->so_type) {
     506             :                 error = EPROTOTYPE;
     507           0 :                 goto bad;
     508             :         }
     509           0 :         if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
     510           0 :                 if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
     511           0 :                     (so3 = sonewconn(so2, 0)) == 0) {
     512             :                         error = ECONNREFUSED;
     513           0 :                         goto bad;
     514             :                 }
     515           0 :                 unp = sotounpcb(so);
     516           0 :                 unp2 = sotounpcb(so2);
     517           0 :                 unp3 = sotounpcb(so3);
     518           0 :                 if (unp2->unp_addr)
     519           0 :                         unp3->unp_addr =
     520           0 :                             m_copym(unp2->unp_addr, 0, M_COPYALL, M_NOWAIT);
     521           0 :                 unp3->unp_connid.uid = p->p_ucred->cr_uid;
     522           0 :                 unp3->unp_connid.gid = p->p_ucred->cr_gid;
     523           0 :                 unp3->unp_connid.pid = p->p_p->ps_pid;
     524           0 :                 unp3->unp_flags |= UNP_FEIDS;
     525             :                 so2 = so3;
     526           0 :                 if (unp2->unp_flags & UNP_FEIDSBIND) {
     527           0 :                         unp->unp_connid = unp2->unp_connid;
     528           0 :                         unp->unp_flags |= UNP_FEIDS;
     529           0 :                 }
     530             :         }
     531           0 :         error = unp_connect2(so, so2);
     532             : bad:
     533           0 :         vput(vp);
     534           0 :         return (error);
     535           0 : }
     536             : 
     537             : int
     538           0 : unp_connect2(struct socket *so, struct socket *so2)
     539             : {
     540           0 :         struct unpcb *unp = sotounpcb(so);
     541             :         struct unpcb *unp2;
     542             : 
     543           0 :         if (so2->so_type != so->so_type)
     544           0 :                 return (EPROTOTYPE);
     545           0 :         unp2 = sotounpcb(so2);
     546           0 :         unp->unp_conn = unp2;
     547           0 :         switch (so->so_type) {
     548             : 
     549             :         case SOCK_DGRAM:
     550           0 :                 SLIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_nextref);
     551           0 :                 soisconnected(so);
     552           0 :                 break;
     553             : 
     554             :         case SOCK_STREAM:
     555             :         case SOCK_SEQPACKET:
     556           0 :                 unp2->unp_conn = unp;
     557           0 :                 soisconnected(so);
     558           0 :                 soisconnected(so2);
     559           0 :                 break;
     560             : 
     561             :         default:
     562           0 :                 panic("unp_connect2");
     563             :         }
     564           0 :         return (0);
     565           0 : }
     566             : 
     567             : void
     568           0 : unp_disconnect(struct unpcb *unp)
     569             : {
     570           0 :         struct unpcb *unp2 = unp->unp_conn;
     571             : 
     572           0 :         if (unp2 == NULL)
     573           0 :                 return;
     574           0 :         unp->unp_conn = NULL;
     575           0 :         switch (unp->unp_socket->so_type) {
     576             : 
     577             :         case SOCK_DGRAM:
     578           0 :                 SLIST_REMOVE(&unp2->unp_refs, unp, unpcb, unp_nextref);
     579           0 :                 unp->unp_socket->so_state &= ~SS_ISCONNECTED;
     580           0 :                 break;
     581             : 
     582             :         case SOCK_STREAM:
     583             :         case SOCK_SEQPACKET:
     584           0 :                 unp->unp_socket->so_snd.sb_mbcnt = 0;
     585           0 :                 unp->unp_socket->so_snd.sb_cc = 0;
     586           0 :                 soisdisconnected(unp->unp_socket);
     587           0 :                 unp2->unp_conn = NULL;
     588           0 :                 unp2->unp_socket->so_snd.sb_mbcnt = 0;
     589           0 :                 unp2->unp_socket->so_snd.sb_cc = 0;
     590           0 :                 soisdisconnected(unp2->unp_socket);
     591           0 :                 break;
     592             :         }
     593           0 : }
     594             : 
     595             : void
     596           0 : unp_shutdown(struct unpcb *unp)
     597             : {
     598             :         struct socket *so;
     599             : 
     600           0 :         switch (unp->unp_socket->so_type) {
     601             :         case SOCK_STREAM:
     602             :         case SOCK_SEQPACKET:
     603           0 :                 if (unp->unp_conn && (so = unp->unp_conn->unp_socket))
     604           0 :                         socantrcvmore(so);
     605             :                 break;
     606             :         default:
     607             :                 break;
     608             :         }
     609           0 : }
     610             : 
     611             : void
     612           0 : unp_drop(struct unpcb *unp, int errno)
     613             : {
     614           0 :         struct socket *so = unp->unp_socket;
     615             : 
     616           0 :         KERNEL_ASSERT_LOCKED();
     617             : 
     618           0 :         so->so_error = errno;
     619           0 :         unp_disconnect(unp);
     620           0 :         if (so->so_head) {
     621           0 :                 so->so_pcb = NULL;
     622             :                 /*
     623             :                  * As long as the KERNEL_LOCK() is the default lock for Unix
     624             :                  * sockets, do not release it.
     625             :                  */
     626           0 :                 sofree(so, SL_NOUNLOCK);
     627           0 :                 m_freem(unp->unp_addr);
     628           0 :                 free(unp, M_PCB, sizeof *unp);
     629           0 :         }
     630           0 : }
     631             : 
     632             : #ifdef notdef
     633             : unp_drain(void)
     634             : {
     635             : 
     636             : }
     637             : #endif
     638             : 
     639             : extern  struct domain unixdomain;
     640             : 
     641             : static struct unpcb *
     642           0 : fptounp(struct file *fp)
     643             : {
     644             :         struct socket *so;
     645             : 
     646           0 :         if (fp->f_type != DTYPE_SOCKET)
     647           0 :                 return (NULL);
     648           0 :         if ((so = fp->f_data) == NULL)
     649           0 :                 return (NULL);
     650           0 :         if (so->so_proto->pr_domain != &unixdomain)
     651           0 :                 return (NULL);
     652           0 :         return (sotounpcb(so));
     653           0 : }
     654             : 
     655             : int
     656           0 : unp_externalize(struct mbuf *rights, socklen_t controllen, int flags)
     657             : {
     658           0 :         struct proc *p = curproc;               /* XXX */
     659           0 :         struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
     660           0 :         struct filedesc *fdp = p->p_fd;
     661             :         int i, *fds = NULL;
     662             :         struct fdpass *rp;
     663             :         struct file *fp;
     664             :         int nfds, error = 0;
     665             : 
     666           0 :         nfds = (cm->cmsg_len - CMSG_ALIGN(sizeof(*cm))) /
     667             :             sizeof(struct fdpass);
     668           0 :         if (controllen < CMSG_ALIGN(sizeof(struct cmsghdr)))
     669           0 :                 controllen = 0;
     670             :         else
     671           0 :                 controllen -= CMSG_ALIGN(sizeof(struct cmsghdr));
     672           0 :         if (nfds > controllen / sizeof(int)) {
     673             :                 error = EMSGSIZE;
     674           0 :                 goto restart;
     675             :         }
     676             : 
     677             :         /* Make sure the recipient should be able to see the descriptors.. */
     678           0 :         rp = (struct fdpass *)CMSG_DATA(cm);
     679           0 :         for (i = 0; i < nfds; i++) {
     680           0 :                 fp = rp->fp;
     681           0 :                 rp++;
     682           0 :                 error = pledge_recvfd(p, fp);
     683           0 :                 if (error)
     684             :                         break;
     685             : 
     686             :                 /*
     687             :                  * No to block devices.  If passing a directory,
     688             :                  * make sure that it is underneath the root.
     689             :                  */
     690           0 :                 if (fdp->fd_rdir != NULL && fp->f_type == DTYPE_VNODE) {
     691           0 :                         struct vnode *vp = (struct vnode *)fp->f_data;
     692             : 
     693           0 :                         if (vp->v_type == VBLK ||
     694           0 :                             (vp->v_type == VDIR &&
     695           0 :                             !vn_isunder(vp, fdp->fd_rdir, p))) {
     696             :                                 error = EPERM;
     697           0 :                                 break;
     698             :                         }
     699           0 :                 }
     700             :         }
     701             : 
     702           0 :         fds = mallocarray(nfds, sizeof(int), M_TEMP, M_WAITOK);
     703             : 
     704             : restart:
     705           0 :         fdplock(fdp);
     706           0 :         if (error != 0) {
     707           0 :                 if (nfds > 0) {
     708           0 :                         rp = ((struct fdpass *)CMSG_DATA(cm));
     709           0 :                         unp_discard(rp, nfds);
     710           0 :                 }
     711             :                 goto out;
     712             :         }
     713             : 
     714             :         /*
     715             :          * First loop -- allocate file descriptor table slots for the
     716             :          * new descriptors.
     717             :          */
     718           0 :         rp = ((struct fdpass *)CMSG_DATA(cm));
     719           0 :         for (i = 0; i < nfds; i++) {
     720           0 :                 if ((error = fdalloc(p, 0, &fds[i])) != 0) {
     721             :                         /*
     722             :                          * Back out what we've done so far.
     723             :                          */
     724           0 :                         for (--i; i >= 0; i--)
     725           0 :                                 fdremove(fdp, fds[i]);
     726             : 
     727           0 :                         if (error == ENOSPC) {
     728           0 :                                 fdexpand(p);
     729             :                                 error = 0;
     730           0 :                         } else {
     731             :                                 /*
     732             :                                  * This is the error that has historically
     733             :                                  * been returned, and some callers may
     734             :                                  * expect it.
     735             :                                  */
     736             :                                 error = EMSGSIZE;
     737             :                         }
     738           0 :                         fdpunlock(fdp);
     739           0 :                         goto restart;
     740             :                 }
     741             : 
     742             :                 /*
     743             :                  * Make the slot reference the descriptor so that
     744             :                  * fdalloc() works properly.. We finalize it all
     745             :                  * in the loop below.
     746             :                  */
     747           0 :                 mtx_enter(&fdp->fd_fplock);
     748           0 :                 KASSERT(fdp->fd_ofiles[fds[i]] == NULL);
     749           0 :                 fdp->fd_ofiles[fds[i]] = rp->fp;
     750           0 :                 mtx_leave(&fdp->fd_fplock);
     751             : 
     752           0 :                 fdp->fd_ofileflags[fds[i]] = (rp->flags & UF_PLEDGED);
     753           0 :                 if (flags & MSG_CMSG_CLOEXEC)
     754           0 :                         fdp->fd_ofileflags[fds[i]] |= UF_EXCLOSE;
     755             : 
     756           0 :                 rp++;
     757             :         }
     758             : 
     759             :         /*
     760             :          * Now that adding them has succeeded, update all of the
     761             :          * descriptor passing state.
     762             :          */
     763             :         rp = (struct fdpass *)CMSG_DATA(cm);
     764           0 :         for (i = 0; i < nfds; i++) {
     765             :                 struct unpcb *unp;
     766             : 
     767           0 :                 fp = rp->fp;
     768           0 :                 rp++;
     769           0 :                 if ((unp = fptounp(fp)) != NULL)
     770           0 :                         unp->unp_msgcount--;
     771           0 :                 unp_rights--;
     772             :         }
     773             : 
     774             :         /*
     775             :          * Copy temporary array to message and adjust length, in case of
     776             :          * transition from large struct file pointers to ints.
     777             :          */
     778           0 :         memcpy(CMSG_DATA(cm), fds, nfds * sizeof(int));
     779           0 :         cm->cmsg_len = CMSG_LEN(nfds * sizeof(int));
     780           0 :         rights->m_len = CMSG_LEN(nfds * sizeof(int));
     781             :  out:
     782           0 :         fdpunlock(fdp);
     783           0 :         if (fds != NULL)
     784           0 :                 free(fds, M_TEMP, nfds * sizeof(int));
     785           0 :         return (error);
     786             : }
     787             : 
     788             : int
     789           0 : unp_internalize(struct mbuf *control, struct proc *p)
     790             : {
     791           0 :         struct filedesc *fdp = p->p_fd;
     792           0 :         struct cmsghdr *cm = mtod(control, struct cmsghdr *);
     793             :         struct fdpass *rp;
     794             :         struct file *fp;
     795             :         struct unpcb *unp;
     796             :         int i, error;
     797             :         int nfds, *ip, fd, neededspace;
     798             : 
     799             :         /*
     800             :          * Check for two potential msg_controllen values because
     801             :          * IETF stuck their nose in a place it does not belong.
     802             :          */ 
     803           0 :         if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
     804           0 :             !(cm->cmsg_len == control->m_len ||
     805           0 :             control->m_len == CMSG_ALIGN(cm->cmsg_len)))
     806           0 :                 return (EINVAL);
     807           0 :         nfds = (cm->cmsg_len - CMSG_ALIGN(sizeof(*cm))) / sizeof (int);
     808             : 
     809           0 :         if (unp_rights + nfds > maxfiles / 10)
     810           0 :                 return (EMFILE);
     811             : 
     812             :         /* Make sure we have room for the struct file pointers */
     813             : morespace:
     814           0 :         neededspace = CMSG_SPACE(nfds * sizeof(struct fdpass)) -
     815           0 :             control->m_len;
     816           0 :         if (neededspace > M_TRAILINGSPACE(control)) {
     817             :                 char *tmp;
     818             :                 /* if we already have a cluster, the message is just too big */
     819           0 :                 if (control->m_flags & M_EXT)
     820           0 :                         return (E2BIG);
     821             : 
     822             :                 /* copy cmsg data temporarily out of the mbuf */
     823           0 :                 tmp = malloc(control->m_len, M_TEMP, M_WAITOK);
     824           0 :                 memcpy(tmp, mtod(control, caddr_t), control->m_len);
     825             : 
     826             :                 /* allocate a cluster and try again */
     827           0 :                 MCLGET(control, M_WAIT);
     828           0 :                 if ((control->m_flags & M_EXT) == 0) {
     829           0 :                         free(tmp, M_TEMP, control->m_len);
     830           0 :                         return (ENOBUFS);       /* allocation failed */
     831             :                 }
     832             : 
     833             :                 /* copy the data back into the cluster */
     834           0 :                 cm = mtod(control, struct cmsghdr *);
     835           0 :                 memcpy(cm, tmp, control->m_len);
     836           0 :                 free(tmp, M_TEMP, control->m_len);
     837           0 :                 goto morespace;
     838             :         }
     839             : 
     840             :         /* adjust message & mbuf to note amount of space actually used. */
     841           0 :         cm->cmsg_len = CMSG_LEN(nfds * sizeof(struct fdpass));
     842           0 :         control->m_len = CMSG_SPACE(nfds * sizeof(struct fdpass));
     843             : 
     844           0 :         ip = ((int *)CMSG_DATA(cm)) + nfds - 1;
     845           0 :         rp = ((struct fdpass *)CMSG_DATA(cm)) + nfds - 1;
     846           0 :         fdplock(fdp);
     847           0 :         for (i = 0; i < nfds; i++) {
     848           0 :                 memcpy(&fd, ip, sizeof fd);
     849           0 :                 ip--;
     850           0 :                 if ((fp = fd_getfile(fdp, fd)) == NULL) {
     851             :                         error = EBADF;
     852           0 :                         goto fail;
     853             :                 }
     854           0 :                 if (fp->f_count >= FDUP_MAX_COUNT) {
     855             :                         error = EDEADLK;
     856           0 :                         goto fail;
     857             :                 }
     858           0 :                 error = pledge_sendfd(p, fp);
     859           0 :                 if (error)
     860             :                         goto fail;
     861             : 
     862             :                 /* kqueue descriptors cannot be copied */
     863           0 :                 if (fp->f_type == DTYPE_KQUEUE) {
     864             :                         error = EINVAL;
     865           0 :                         goto fail;
     866             :                 }
     867           0 :                 rp->fp = fp;
     868           0 :                 rp->flags = fdp->fd_ofileflags[fd] & UF_PLEDGED;
     869           0 :                 rp--;
     870           0 :                 if ((unp = fptounp(fp)) != NULL) {
     871           0 :                         unp->unp_file = fp;
     872           0 :                         unp->unp_msgcount++;
     873           0 :                 }
     874           0 :                 unp_rights++;
     875             :         }
     876           0 :         fdpunlock(fdp);
     877           0 :         return (0);
     878             : fail:
     879           0 :         fdpunlock(fdp);
     880           0 :         if (fp != NULL)
     881           0 :                 FRELE(fp, p);
     882             :         /* Back out what we just did. */
     883           0 :         for ( ; i > 0; i--) {
     884           0 :                 rp++;
     885           0 :                 fp = rp->fp;
     886           0 :                 if ((unp = fptounp(fp)) != NULL)
     887           0 :                         unp->unp_msgcount--;
     888           0 :                 FRELE(fp, p);
     889           0 :                 unp_rights--;
     890             :         }
     891             : 
     892           0 :         return (error);
     893           0 : }
     894             : 
     895             : int     unp_defer, unp_gcing;
     896             : 
     897             : void
     898           0 : unp_gc(void *arg __unused)
     899             : {
     900             :         struct unp_deferral *defer;
     901             :         struct file *fp;
     902             :         struct socket *so;
     903             :         struct unpcb *unp;
     904             :         int nunref, i;
     905             : 
     906           0 :         if (unp_gcing)
     907           0 :                 return;
     908           0 :         unp_gcing = 1;
     909             : 
     910             :         /* close any fds on the deferred list */
     911           0 :         while ((defer = SLIST_FIRST(&unp_deferred)) != NULL) {
     912           0 :                 SLIST_REMOVE_HEAD(&unp_deferred, ud_link);
     913           0 :                 for (i = 0; i < defer->ud_n; i++) {
     914           0 :                         fp = defer->ud_fp[i].fp;
     915           0 :                         if (fp == NULL)
     916             :                                 continue;
     917             :                          /* closef() expects a refcount of 2 */
     918           0 :                         FREF(fp);
     919           0 :                         if ((unp = fptounp(fp)) != NULL)
     920           0 :                                 unp->unp_msgcount--;
     921           0 :                         unp_rights--;
     922           0 :                         (void) closef(fp, NULL);
     923           0 :                 }
     924           0 :                 free(defer, M_TEMP, sizeof(*defer) +
     925           0 :                     sizeof(struct fdpass) * defer->ud_n);
     926             :         }
     927             : 
     928           0 :         unp_defer = 0;
     929           0 :         LIST_FOREACH(unp, &unp_head, unp_link)
     930           0 :                 unp->unp_flags &= ~(UNP_GCMARK | UNP_GCDEFER | UNP_GCDEAD);
     931           0 :         do {
     932             :                 nunref = 0;
     933           0 :                 LIST_FOREACH(unp, &unp_head, unp_link) {
     934           0 :                         fp = unp->unp_file;
     935           0 :                         if (unp->unp_flags & UNP_GCDEFER) {
     936             :                                 /*
     937             :                                  * This socket is referenced by another
     938             :                                  * socket which is known to be live,
     939             :                                  * so it's certainly live.
     940             :                                  */
     941           0 :                                 unp->unp_flags &= ~UNP_GCDEFER;
     942           0 :                                 unp_defer--;
     943           0 :                         } else if (unp->unp_flags & UNP_GCMARK) {
     944             :                                 /* marked as live in previous pass */
     945             :                                 continue;
     946           0 :                         } else if (fp == NULL) {
     947             :                                 /* not being passed, so can't be in loop */
     948           0 :                         } else if (fp->f_count == 0) {
     949             :                                 /*
     950             :                                  * Already being closed, let normal close
     951             :                                  * path take its course
     952             :                                  */
     953             :                         } else {
     954             :                                 /*
     955             :                                  * Unreferenced by other sockets so far,
     956             :                                  * so if all the references (f_count) are
     957             :                                  * from passing (unp_msgcount) then this
     958             :                                  * socket is prospectively dead
     959             :                                  */
     960           0 :                                 if (fp->f_count == unp->unp_msgcount) {
     961           0 :                                         nunref++;
     962           0 :                                         unp->unp_flags |= UNP_GCDEAD;
     963           0 :                                         continue;
     964             :                                 }
     965             :                         }
     966             : 
     967             :                         /*
     968             :                          * This is the first time we've seen this socket on
     969             :                          * the mark pass and known it has a live reference,
     970             :                          * so mark it, then scan its receive buffer for
     971             :                          * sockets and note them as deferred (== referenced,
     972             :                          * but not yet marked).
     973             :                          */
     974           0 :                         unp->unp_flags |= UNP_GCMARK;
     975             : 
     976           0 :                         so = unp->unp_socket;
     977           0 :                         unp_scan(so->so_rcv.sb_mb, unp_mark);
     978           0 :                 }
     979           0 :         } while (unp_defer);
     980             : 
     981             :         /*
     982             :          * If there are any unreferenced sockets, then for each dispose
     983             :          * of files in its receive buffer and then close it.
     984             :          */
     985           0 :         if (nunref) {
     986           0 :                 LIST_FOREACH(unp, &unp_head, unp_link) {
     987           0 :                         if (unp->unp_flags & UNP_GCDEAD)
     988           0 :                                 unp_scan(unp->unp_socket->so_rcv.sb_mb,
     989             :                                     unp_discard);
     990             :                 }
     991             :         }
     992           0 :         unp_gcing = 0;
     993           0 : }
     994             : 
     995             : void
     996           0 : unp_dispose(struct mbuf *m)
     997             : {
     998             : 
     999           0 :         if (m)
    1000           0 :                 unp_scan(m, unp_discard);
    1001           0 : }
    1002             : 
    1003             : void
    1004           0 : unp_scan(struct mbuf *m0, void (*op)(struct fdpass *, int))
    1005             : {
    1006             :         struct mbuf *m;
    1007             :         struct fdpass *rp;
    1008             :         struct cmsghdr *cm;
    1009             :         int qfds;
    1010             : 
    1011           0 :         while (m0) {
    1012           0 :                 for (m = m0; m; m = m->m_next) {
    1013           0 :                         if (m->m_type == MT_CONTROL &&
    1014           0 :                             m->m_len >= sizeof(*cm)) {
    1015           0 :                                 cm = mtod(m, struct cmsghdr *);
    1016           0 :                                 if (cm->cmsg_level != SOL_SOCKET ||
    1017           0 :                                     cm->cmsg_type != SCM_RIGHTS)
    1018             :                                         continue;
    1019           0 :                                 qfds = (cm->cmsg_len - CMSG_ALIGN(sizeof *cm))
    1020           0 :                                     / sizeof(struct fdpass);
    1021           0 :                                 if (qfds > 0) {
    1022           0 :                                         rp = (struct fdpass *)CMSG_DATA(cm);
    1023           0 :                                         op(rp, qfds);
    1024           0 :                                 }
    1025             :                                 break;          /* XXX, but saves time */
    1026             :                         }
    1027             :                 }
    1028           0 :                 m0 = m0->m_nextpkt;
    1029             :         }
    1030           0 : }
    1031             : 
    1032             : void
    1033           0 : unp_mark(struct fdpass *rp, int nfds)
    1034             : {
    1035             :         struct unpcb *unp;
    1036             :         int i;
    1037             : 
    1038           0 :         for (i = 0; i < nfds; i++) {
    1039           0 :                 if (rp[i].fp == NULL)
    1040             :                         continue;
    1041             : 
    1042           0 :                 unp = fptounp(rp[i].fp);
    1043           0 :                 if (unp == NULL)
    1044             :                         continue;
    1045             : 
    1046           0 :                 if (unp->unp_flags & (UNP_GCMARK|UNP_GCDEFER))
    1047             :                         continue;
    1048             : 
    1049           0 :                 unp_defer++;
    1050           0 :                 unp->unp_flags |= UNP_GCDEFER;
    1051           0 :                 unp->unp_flags &= ~UNP_GCDEAD;
    1052           0 :         }
    1053           0 : }
    1054             : 
    1055             : void
    1056           0 : unp_discard(struct fdpass *rp, int nfds)
    1057             : {
    1058             :         struct unp_deferral *defer;
    1059             : 
    1060             :         /* copy the file pointers to a deferral structure */
    1061           0 :         defer = malloc(sizeof(*defer) + sizeof(*rp) * nfds, M_TEMP, M_WAITOK);
    1062           0 :         defer->ud_n = nfds;
    1063           0 :         memcpy(&defer->ud_fp[0], rp, sizeof(*rp) * nfds);
    1064           0 :         memset(rp, 0, sizeof(*rp) * nfds);
    1065           0 :         SLIST_INSERT_HEAD(&unp_deferred, defer, ud_link);
    1066             : 
    1067           0 :         task_add(systq, &unp_gc_task);
    1068           0 : }
    1069             : 
    1070             : int
    1071           0 : unp_nam2sun(struct mbuf *nam, struct sockaddr_un **sun, size_t *pathlen)
    1072             : {
    1073           0 :         struct sockaddr *sa = mtod(nam, struct sockaddr *);
    1074             :         size_t size, len;
    1075             : 
    1076           0 :         if (nam->m_len < offsetof(struct sockaddr, sa_data))
    1077           0 :                 return EINVAL;
    1078           0 :         if (sa->sa_family != AF_UNIX)
    1079           0 :                 return EAFNOSUPPORT;
    1080           0 :         if (sa->sa_len != nam->m_len)
    1081           0 :                 return EINVAL;
    1082           0 :         if (sa->sa_len > sizeof(struct sockaddr_un))
    1083           0 :                 return EINVAL;
    1084           0 :         *sun = (struct sockaddr_un *)sa;
    1085             : 
    1086             :         /* ensure that sun_path is NUL terminated and fits */
    1087           0 :         size = (*sun)->sun_len - offsetof(struct sockaddr_un, sun_path);
    1088           0 :         len = strnlen((*sun)->sun_path, size);
    1089           0 :         if (len == sizeof((*sun)->sun_path))
    1090           0 :                 return EINVAL;
    1091           0 :         if (len == size) {
    1092           0 :                 if (M_TRAILINGSPACE(nam) == 0)
    1093           0 :                         return EINVAL;
    1094           0 :                 nam->m_len++;
    1095           0 :                 (*sun)->sun_len++;
    1096           0 :                 (*sun)->sun_path[len] = '\0';
    1097           0 :         }
    1098           0 :         if (pathlen != NULL)
    1099           0 :                 *pathlen = len;
    1100             : 
    1101           0 :         return 0;
    1102           0 : }

Generated by: LCOV version 1.13