portal_vnops.c

来自「早期freebsd实现」· C语言 代码 · 共 708 行 · 第 1/2 页

C
708
字号
/* * Copyright (c) 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software donated to Berkeley by * Jan-Simon Pendry. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)portal_vnops.c	8.8 (Berkeley) 1/21/94 * * $Id: portal_vnops.c,v 1.4 1992/05/30 10:05:24 jsp Exp jsp $ *//* * Portal Filesystem */#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/types.h>#include <sys/time.h>#include <sys/proc.h>#include <sys/filedesc.h>#include <sys/vnode.h>#include <sys/file.h>#include <sys/stat.h>#include <sys/mount.h>#include <sys/malloc.h>#include <sys/namei.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/un.h>#include <sys/unpcb.h>#include <miscfs/portal/portal.h>static int portal_fileid = PORTAL_ROOTFILEID+1;static voidportal_closefd(p, fd)	struct proc *p;	int fd;{	int error;	struct {		int fd;	} ua;	int rc;	ua.fd = fd;	error = close(p, &ua, &rc);	/*	 * We should never get an error, and there isn't anything	 * we could do if we got one, so just print a message.	 */	if (error)		printf("portal_closefd: error = %d\n", error);}/* * vp is the current namei directory * cnp is the name to locate in that directory... */intportal_lookup(ap)	struct vop_lookup_args /* {		struct vnode * a_dvp;		struct vnode ** a_vpp;		struct componentname * a_cnp;	} */ *ap;{	char *pname = ap->a_cnp->cn_nameptr;	struct portalnode *pt;	int error;	struct vnode *fvp = 0;	char *path;	int size;	if (ap->a_cnp->cn_namelen == 1 && *pname == '.') {		*ap->a_vpp = ap->a_dvp;		VREF(ap->a_dvp);		/*VOP_LOCK(ap->a_dvp);*/		return (0);	}	error = getnewvnode(VT_PORTAL, ap->a_dvp->v_mount, portal_vnodeop_p, &fvp);	if (error)		goto bad;	fvp->v_type = VREG;	MALLOC(fvp->v_data, void *, sizeof(struct portalnode),		M_TEMP, M_WAITOK);	pt = VTOPORTAL(fvp);	/*	 * Save all of the remaining pathname and	 * advance the namei next pointer to the end	 * of the string.	 */	for (size = 0, path = pname; *path; path++)		size++;	ap->a_cnp->cn_consume = size - ap->a_cnp->cn_namelen;	pt->pt_arg = malloc(size+1, M_TEMP, M_WAITOK);	pt->pt_size = size+1;	bcopy(pname, pt->pt_arg, pt->pt_size);	pt->pt_fileid = portal_fileid++;	*ap->a_vpp = fvp;	/*VOP_LOCK(fvp);*/	return (0);bad:;	if (fvp) {		vrele(fvp);	}	*ap->a_vpp = NULL;	return (error);}static intportal_connect(so, so2)	struct socket *so;	struct socket *so2;{	/* from unp_connect, bypassing the namei stuff... */	struct socket *so3;	struct unpcb *unp2;	struct unpcb *unp3;	if (so2 == 0)		return (ECONNREFUSED);	if (so->so_type != so2->so_type)		return (EPROTOTYPE);	if ((so2->so_options & SO_ACCEPTCONN) == 0)		return (ECONNREFUSED);	if ((so3 = sonewconn(so2, 0)) == 0)		return (ECONNREFUSED);	unp2 = sotounpcb(so2);	unp3 = sotounpcb(so3);	if (unp2->unp_addr)		unp3->unp_addr = m_copy(unp2->unp_addr, 0, (int)M_COPYALL);	so2 = so3;	return (unp_connect2(so, so2));}intportal_open(ap)	struct vop_open_args /* {		struct vnode *a_vp;		int  a_mode;		struct ucred *a_cred;		struct proc *a_p;	} */ *ap;{	struct socket *so = 0;	struct portalnode *pt;	struct proc *p = ap->a_p;	struct vnode *vp = ap->a_vp;	int s;	struct uio auio;	struct iovec aiov[2];	int res;	struct mbuf *cm = 0;	struct cmsghdr *cmsg;	int newfds;	int *ip;	int fd;	int error;	int len;	struct portalmount *fmp;	struct file *fp;	struct portal_cred pcred;	/*	 * Nothing to do when opening the root node.	 */	if (vp->v_flag & VROOT)		return (0);	/*	 * Can't be opened unless the caller is set up	 * to deal with the side effects.  Check for this	 * by testing whether the p_dupfd has been set.	 */	if (p->p_dupfd >= 0)		return (ENODEV);	pt = VTOPORTAL(vp);	fmp = VFSTOPORTAL(vp->v_mount);	/*	 * Create a new socket.	 */	error = socreate(AF_UNIX, &so, SOCK_STREAM, 0);	if (error)		goto bad;	/*	 * Reserve some buffer space	 */	res = pt->pt_size + sizeof(pcred) + 512;	/* XXX */	error = soreserve(so, res, res);	if (error)		goto bad;	/*	 * Kick off connection	 */	error = portal_connect(so, (struct socket *)fmp->pm_server->f_data);	if (error)		goto bad;	/*	 * Wait for connection to complete	 */	/*	 * XXX: Since the mount point is holding a reference on the	 * underlying server socket, it is not easy to find out whether	 * the server process is still running.  To handle this problem	 * we loop waiting for the new socket to be connected (something	 * which will only happen if the server is still running) or for	 * the reference count on the server socket to drop to 1, which	 * will happen if the server dies.  Sleep for 5 second intervals	 * and keep polling the reference count.   XXX.	 */	s = splnet();	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {		if (fmp->pm_server->f_count == 1) {			error = ECONNREFUSED;			splx(s);			goto bad;		}		(void) tsleep((caddr_t) &so->so_timeo, PSOCK, "portalcon", 5 * hz);	}	splx(s);	if (so->so_error) {		error = so->so_error;		goto bad;	}			/*	 * Set miscellaneous flags	 */	so->so_rcv.sb_timeo = 0;	so->so_snd.sb_timeo = 0;	so->so_rcv.sb_flags |= SB_NOINTR;	so->so_snd.sb_flags |= SB_NOINTR;	pcred.pcr_flag = ap->a_mode;	pcred.pcr_uid = ap->a_cred->cr_uid;	pcred.pcr_ngroups = ap->a_cred->cr_ngroups;	bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));	aiov[0].iov_base = (caddr_t) &pcred;	aiov[0].iov_len = sizeof(pcred);	aiov[1].iov_base = pt->pt_arg;	aiov[1].iov_len = pt->pt_size;	auio.uio_iov = aiov;	auio.uio_iovcnt = 2;	auio.uio_rw = UIO_WRITE;	auio.uio_segflg = UIO_SYSSPACE;	auio.uio_procp = p;	auio.uio_offset = 0;	auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len;	error = sosend(so, (struct mbuf *) 0, &auio,			(struct mbuf *) 0, (struct mbuf *) 0, 0);	if (error)		goto bad;	len = auio.uio_resid = sizeof(int);	do {		struct mbuf *m = 0;		int flags = MSG_WAITALL;		error = soreceive(so, (struct mbuf **) 0, &auio,					&m, &cm, &flags);		if (error)			goto bad;		/*		 * Grab an error code from the mbuf.		 */		if (m) {			m = m_pullup(m, sizeof(int));	/* Needed? */			if (m) {				error = *(mtod(m, int *));				m_freem(m);			} else {				error = EINVAL;			}		} else {			if (cm == 0) {				error = ECONNRESET;	 /* XXX */#ifdef notdef				break;#endif			}		}	} while (cm == 0 && auio.uio_resid == len && !error);	if (cm == 0)		goto bad;	if (auio.uio_resid) {		error = 0;#ifdef notdef		error = EMSGSIZE;		goto bad;#endif	}	/*	 * XXX: Break apart the control message, and retrieve the	 * received file descriptor.  Note that more than one descriptor	 * may have been received, or that the rights chain may have more	 * than a single mbuf in it.  What to do?	 */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?