vfs_lookup.c revision 144833
1139804Simp/*-
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
51541Srgrimes * All or some portions of this file are derived from material licensed
61541Srgrimes * to the University of California by American Telephone and Telegraph
71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
81541Srgrimes * the permission of UNIX System Laboratories, Inc.
91541Srgrimes *
101541Srgrimes * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 4. Neither the name of the University nor the names of its contributors
191541Srgrimes *    may be used to endorse or promote products derived from this software
201541Srgrimes *    without specific prior written permission.
211541Srgrimes *
221541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321541Srgrimes * SUCH DAMAGE.
331541Srgrimes *
341541Srgrimes *	@(#)vfs_lookup.c	8.4 (Berkeley) 2/16/94
351541Srgrimes */
361541Srgrimes
37116182Sobrien#include <sys/cdefs.h>
38116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/vfs_lookup.c 144833 2005-04-09 11:53:16Z jeff $");
39116182Sobrien
4013203Swollman#include "opt_ktrace.h"
41101127Srwatson#include "opt_mac.h"
42144613Sjeff#include "opt_vfs.h"
4313203Swollman
441541Srgrimes#include <sys/param.h>
452112Swollman#include <sys/systm.h>
4669664Speter#include <sys/kernel.h>
4776166Smarkm#include <sys/lock.h>
48101127Srwatson#include <sys/mac.h>
4989316Salfred#include <sys/mutex.h>
501541Srgrimes#include <sys/namei.h>
511541Srgrimes#include <sys/vnode.h>
521541Srgrimes#include <sys/mount.h>
531541Srgrimes#include <sys/filedesc.h>
541541Srgrimes#include <sys/proc.h>
55141471Sjhb#include <sys/syscallsubr.h>
56144613Sjeff#include <sys/sysctl.h>
571541Srgrimes#ifdef KTRACE
581541Srgrimes#include <sys/ktrace.h>
591541Srgrimes#endif
601541Srgrimes
6192751Sjeff#include <vm/uma.h>
6232011Sbde
63138345Sphk#define NAMEI_DIAGNOSTIC 1
64138345Sphk#undef NAMEI_DIAGNOSTIC
65138345Sphk
661541Srgrimes/*
6769664Speter * Allocation zone for namei
6869664Speter */
6992751Sjeffuma_zone_t namei_zone;
7069664Speter
7169664Speterstatic void
7269664Speternameiinit(void *dummy __unused)
7369664Speter{
7492654Sjeff	namei_zone = uma_zcreate("NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL,
7592654Sjeff	    UMA_ALIGN_PTR, 0);
7669664Speter
7769664Speter}
7869664SpeterSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL)
7969664Speter
80144613Sjeff#ifdef LOOKUP_SHARED
81144613Sjeffstatic int lookup_shared = 1;
82144613Sjeff#else
83144613Sjeffstatic int lookup_shared = 0;
84144613Sjeff#endif
85144613SjeffSYSCTL_INT(_vfs, OID_AUTO, lookup_shared, CTLFLAG_RW, &lookup_shared, 0,
86144613Sjeff    "Enables/Disables shared locks for path name translation");
87144613Sjeff
8869664Speter/*
891541Srgrimes * Convert a pathname into a pointer to a locked inode.
901541Srgrimes *
911541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed
921541Srgrimes * when they occur at the end of the name translation process.
931541Srgrimes * Symbolic links are always followed for all other pathname
941541Srgrimes * components other than the last.
951541Srgrimes *
961541Srgrimes * The segflg defines whether the name is to be copied from user
971541Srgrimes * space or kernel space.
981541Srgrimes *
991541Srgrimes * Overall outline of namei:
1001541Srgrimes *
1011541Srgrimes *	copy in name
1021541Srgrimes *	get starting directory
1031541Srgrimes *	while (!done && !error) {
1041541Srgrimes *		call lookup to search path.
1051541Srgrimes *		if symbolic link, massage name in buffer and continue
1061541Srgrimes *	}
1071541Srgrimes */
1081541Srgrimesint
1091541Srgrimesnamei(ndp)
1101541Srgrimes	register struct nameidata *ndp;
1111541Srgrimes{
1121541Srgrimes	register struct filedesc *fdp;	/* pointer to file descriptor state */
1131541Srgrimes	register char *cp;		/* pointer into pathname argument */
1141541Srgrimes	register struct vnode *dp;	/* the directory we are searching */
1151541Srgrimes	struct iovec aiov;		/* uio for reading symbolic links */
1161541Srgrimes	struct uio auio;
1171541Srgrimes	int error, linklen;
1181541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
11983366Sjulian	struct thread *td = cnp->cn_thread;
12083366Sjulian	struct proc *p = td->td_proc;
121140714Sjeff	int vfslocked;
1221541Srgrimes
12391419Sjhb	ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred;
12483366Sjulian	KASSERT(cnp->cn_cred && p, ("namei: bad cred/proc"));
12542408Seivind	KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0,
12642453Seivind	    ("namei: nameiop contaminated with flags"));
12742408Seivind	KASSERT((cnp->cn_flags & OPMASK) == 0,
12842453Seivind	    ("namei: flags contaminated with nameiops"));
129144613Sjeff	if (!lookup_shared)
130144613Sjeff		cnp->cn_flags &= ~LOCKSHARED;
13183366Sjulian	fdp = p->p_fd;
1321541Srgrimes
1331541Srgrimes	/*
1341541Srgrimes	 * Get a buffer for the name to be translated, and copy the
1351541Srgrimes	 * name into the buffer.
1361541Srgrimes	 */
1371541Srgrimes	if ((cnp->cn_flags & HASBUF) == 0)
138111119Simp		cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
1391541Srgrimes	if (ndp->ni_segflg == UIO_SYSSPACE)
1401541Srgrimes		error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
14136735Sdfr			    MAXPATHLEN, (size_t *)&ndp->ni_pathlen);
1421541Srgrimes	else
1431541Srgrimes		error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
14436735Sdfr			    MAXPATHLEN, (size_t *)&ndp->ni_pathlen);
14520069Sbde
14620069Sbde	/*
14720069Sbde	 * Don't allow empty pathnames.
14820069Sbde	 */
14920069Sbde	if (!error && *cnp->cn_pnbuf == '\0')
15020069Sbde		error = ENOENT;
15120069Sbde
1521541Srgrimes	if (error) {
15392751Sjeff		uma_zfree(namei_zone, cnp->cn_pnbuf);
154100613Srwatson#ifdef DIAGNOSTIC
155100613Srwatson		cnp->cn_pnbuf = NULL;
156100613Srwatson		cnp->cn_nameptr = NULL;
157100613Srwatson#endif
1581541Srgrimes		ndp->ni_vp = NULL;
1591541Srgrimes		return (error);
1601541Srgrimes	}
1611541Srgrimes	ndp->ni_loopcnt = 0;
1621541Srgrimes#ifdef KTRACE
16397994Sjhb	if (KTRPOINT(td, KTR_NAMEI)) {
16497994Sjhb		KASSERT(cnp->cn_thread == curthread,
16597994Sjhb		    ("namei not using curthread"));
16697994Sjhb		ktrnamei(cnp->cn_pnbuf);
16797994Sjhb	}
1681541Srgrimes#endif
1691541Srgrimes
1701541Srgrimes	/*
1711541Srgrimes	 * Get starting point for the translation.
1721541Srgrimes	 */
17389306Salfred	FILEDESC_LOCK(fdp);
17433360Sdyson	ndp->ni_rootdir = fdp->fd_rdir;
17551649Sphk	ndp->ni_topdir = fdp->fd_jdir;
17633360Sdyson
1771541Srgrimes	dp = fdp->fd_cdir;
178140714Sjeff	vfslocked = VFS_LOCK_GIANT(dp->v_mount);
1791541Srgrimes	VREF(dp);
18089306Salfred	FILEDESC_UNLOCK(fdp);
1811541Srgrimes	for (;;) {
1821541Srgrimes		/*
1831541Srgrimes		 * Check if root directory should replace current directory.
1841541Srgrimes		 * Done at start of translation and after symbolic link.
1851541Srgrimes		 */
1861541Srgrimes		cnp->cn_nameptr = cnp->cn_pnbuf;
1871541Srgrimes		if (*(cnp->cn_nameptr) == '/') {
1881541Srgrimes			vrele(dp);
189140714Sjeff			VFS_UNLOCK_GIANT(vfslocked);
1901541Srgrimes			while (*(cnp->cn_nameptr) == '/') {
1911541Srgrimes				cnp->cn_nameptr++;
1921541Srgrimes				ndp->ni_pathlen--;
1931541Srgrimes			}
1941541Srgrimes			dp = ndp->ni_rootdir;
195140714Sjeff			vfslocked = VFS_LOCK_GIANT(dp->v_mount);
1961541Srgrimes			VREF(dp);
1971541Srgrimes		}
198140714Sjeff		if (vfslocked)
199140714Sjeff			ndp->ni_cnd.cn_flags |= GIANTHELD;
2001541Srgrimes		ndp->ni_startdir = dp;
2013148Sphk		error = lookup(ndp);
2023148Sphk		if (error) {
20392751Sjeff			uma_zfree(namei_zone, cnp->cn_pnbuf);
204100613Srwatson#ifdef DIAGNOSTIC
205100613Srwatson			cnp->cn_pnbuf = NULL;
206100613Srwatson			cnp->cn_nameptr = NULL;
207100613Srwatson#endif
2081541Srgrimes			return (error);
2091541Srgrimes		}
210140714Sjeff		vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
211140714Sjeff		ndp->ni_cnd.cn_flags &= ~GIANTHELD;
2121541Srgrimes		/*
2131541Srgrimes		 * Check for symbolic link
2141541Srgrimes		 */
2151541Srgrimes		if ((cnp->cn_flags & ISSYMLINK) == 0) {
216100613Srwatson			if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) {
21792751Sjeff				uma_zfree(namei_zone, cnp->cn_pnbuf);
218100613Srwatson#ifdef DIAGNOSTIC
219100613Srwatson				cnp->cn_pnbuf = NULL;
220100613Srwatson				cnp->cn_nameptr = NULL;
221100613Srwatson#endif
222100613Srwatson			} else
2231541Srgrimes				cnp->cn_flags |= HASBUF;
22432286Sdyson
225140714Sjeff			if ((cnp->cn_flags & MPSAFE) == 0) {
226140714Sjeff				VFS_UNLOCK_GIANT(vfslocked);
227140714Sjeff			} else if (vfslocked)
228140714Sjeff				ndp->ni_cnd.cn_flags |= GIANTHELD;
2291541Srgrimes			return (0);
2301541Srgrimes		}
2311541Srgrimes		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
2321541Srgrimes			error = ELOOP;
2331541Srgrimes			break;
2341541Srgrimes		}
235101127Srwatson#ifdef MAC
236105479Srwatson		if ((cnp->cn_flags & NOMACCHECK) == 0) {
237105479Srwatson			error = mac_check_vnode_readlink(td->td_ucred,
238105479Srwatson			    ndp->ni_vp);
239105479Srwatson			if (error)
240105479Srwatson				break;
241105479Srwatson		}
242101127Srwatson#endif
2431541Srgrimes		if (ndp->ni_pathlen > 1)
244111119Simp			cp = uma_zalloc(namei_zone, M_WAITOK);
2451541Srgrimes		else
2461541Srgrimes			cp = cnp->cn_pnbuf;
2471541Srgrimes		aiov.iov_base = cp;
2481541Srgrimes		aiov.iov_len = MAXPATHLEN;
2491541Srgrimes		auio.uio_iov = &aiov;
2501541Srgrimes		auio.uio_iovcnt = 1;
2511541Srgrimes		auio.uio_offset = 0;
2521541Srgrimes		auio.uio_rw = UIO_READ;
2531541Srgrimes		auio.uio_segflg = UIO_SYSSPACE;
25483366Sjulian		auio.uio_td = (struct thread *)0;
2551541Srgrimes		auio.uio_resid = MAXPATHLEN;
2563148Sphk		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
2573148Sphk		if (error) {
2581541Srgrimes			if (ndp->ni_pathlen > 1)
25992751Sjeff				uma_zfree(namei_zone, cp);
2601541Srgrimes			break;
2611541Srgrimes		}
2621541Srgrimes		linklen = MAXPATHLEN - auio.uio_resid;
26378692Sdillon		if (linklen == 0) {
26478692Sdillon			if (ndp->ni_pathlen > 1)
26592751Sjeff				uma_zfree(namei_zone, cp);
26678692Sdillon			error = ENOENT;
26778692Sdillon			break;
26878692Sdillon		}
2691541Srgrimes		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
2701541Srgrimes			if (ndp->ni_pathlen > 1)
27192751Sjeff				uma_zfree(namei_zone, cp);
2721541Srgrimes			error = ENAMETOOLONG;
2731541Srgrimes			break;
2741541Srgrimes		}
2751541Srgrimes		if (ndp->ni_pathlen > 1) {
2761541Srgrimes			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
27792751Sjeff			uma_zfree(namei_zone, cnp->cn_pnbuf);
2781541Srgrimes			cnp->cn_pnbuf = cp;
2791541Srgrimes		} else
2801541Srgrimes			cnp->cn_pnbuf[linklen] = '\0';
2811541Srgrimes		ndp->ni_pathlen += linklen;
2821541Srgrimes		vput(ndp->ni_vp);
2831541Srgrimes		dp = ndp->ni_dvp;
2841541Srgrimes	}
28592751Sjeff	uma_zfree(namei_zone, cnp->cn_pnbuf);
286100613Srwatson#ifdef DIAGNOSTIC
287100613Srwatson	cnp->cn_pnbuf = NULL;
288100613Srwatson	cnp->cn_nameptr = NULL;
289100613Srwatson#endif
290144833Sjeff	vput(ndp->ni_vp);
291144833Sjeff	ndp->ni_vp = NULL;
2921541Srgrimes	vrele(ndp->ni_dvp);
293140714Sjeff	VFS_UNLOCK_GIANT(vfslocked);
2941541Srgrimes	return (error);
2951541Srgrimes}
2961541Srgrimes
2971541Srgrimes/*
2981541Srgrimes * Search a pathname.
2991541Srgrimes * This is a very central and rather complicated routine.
3001541Srgrimes *
3011541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
3021541Srgrimes * The starting directory is taken from ni_startdir. The pathname is
3031541Srgrimes * descended until done, or a symbolic link is encountered. The variable
3041541Srgrimes * ni_more is clear if the path is completed; it is set to one if a
3051541Srgrimes * symbolic link needing interpretation is encountered.
3061541Srgrimes *
3071541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
3081541Srgrimes * whether the name is to be looked up, created, renamed, or deleted.
3091541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in
3101541Srgrimes * creating, renaming, or deleting a directory entry may be calculated.
3111541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned
3121541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is
3131541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If
3141541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag
3151541Srgrimes * the target is returned locked, otherwise it is returned unlocked.
3161541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not
3171541Srgrimes * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
3188876Srgrimes *
3191541Srgrimes * Overall outline of lookup:
3201541Srgrimes *
3211541Srgrimes * dirloop:
3221541Srgrimes *	identify next component of name at ndp->ni_ptr
3231541Srgrimes *	handle degenerate case where name is null string
3241541Srgrimes *	if .. and crossing mount points and on mounted filesys, find parent
3251541Srgrimes *	call VOP_LOOKUP routine for next component name
3261541Srgrimes *	    directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
3271541Srgrimes *	    component vnode returned in ni_vp (if it exists), locked.
3281541Srgrimes *	if result vnode is mounted on and crossing mount points,
3291541Srgrimes *	    find mounted on vnode
3301541Srgrimes *	if more components of name, do next level at dirloop
3311541Srgrimes *	return the answer in ni_vp, locked if LOCKLEAF set
3321541Srgrimes *	    if LOCKPARENT set, return locked parent in ni_dvp
3331541Srgrimes *	    if WANTPARENT set, return unlocked parent in ni_dvp
3341541Srgrimes */
3351541Srgrimesint
3361541Srgrimeslookup(ndp)
3371541Srgrimes	register struct nameidata *ndp;
3381541Srgrimes{
3391541Srgrimes	register char *cp;		/* pointer into pathname argument */
3401541Srgrimes	register struct vnode *dp = 0;	/* the directory we are searching */
3411541Srgrimes	struct vnode *tdp;		/* saved dp */
3421541Srgrimes	struct mount *mp;		/* mount table entry */
3431541Srgrimes	int docache;			/* == 0 do not cache last component */
3441541Srgrimes	int wantparent;			/* 1 => wantparent or lockparent flag */
3451541Srgrimes	int rdonly;			/* lookup read-only flag bit */
3469804Sbde	int trailing_slash;
3471541Srgrimes	int error = 0;
34865805Sbp	int dpunlocked = 0;		/* dp has already been unlocked */
3491541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
35083366Sjulian	struct thread *td = cnp->cn_thread;
351140714Sjeff	int vfslocked;
352140714Sjeff	int tvfslocked;
3531541Srgrimes
3541541Srgrimes	/*
3551541Srgrimes	 * Setup: break out flag bits into variables.
3561541Srgrimes	 */
357140714Sjeff	vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
358140714Sjeff	ndp->ni_cnd.cn_flags &= ~GIANTHELD;
3591541Srgrimes	wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
360144229Sjeff	KASSERT(cnp->cn_nameiop == LOOKUP || wantparent,
361144229Sjeff	    ("CREATE, DELETE, RENAME require LOCKPARENT or WANTPARENT."));
3621541Srgrimes	docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
3631541Srgrimes	if (cnp->cn_nameiop == DELETE ||
36422874Sbde	    (wantparent && cnp->cn_nameiop != CREATE &&
36522874Sbde	     cnp->cn_nameiop != LOOKUP))
3661541Srgrimes		docache = 0;
3671541Srgrimes	rdonly = cnp->cn_flags & RDONLY;
368144286Sjeff	cnp->cn_flags &= ~ISSYMLINK;
3691541Srgrimes	ndp->ni_dvp = NULL;
370144286Sjeff	/*
371144286Sjeff	 * We use shared locks until we hit the parent of the last cn then
372144286Sjeff	 * we adjust based on the requesting flags.
373144286Sjeff	 */
374144613Sjeff	if (lookup_shared)
375144613Sjeff		cnp->cn_lkflags = LK_SHARED;
376144613Sjeff	else
377144613Sjeff		cnp->cn_lkflags = LK_EXCLUSIVE;
3781541Srgrimes	dp = ndp->ni_startdir;
3791541Srgrimes	ndp->ni_startdir = NULLVP;
380144286Sjeff	vn_lock(dp, cnp->cn_lkflags | LK_RETRY, td);
3811541Srgrimes
3821541Srgrimesdirloop:
3831541Srgrimes	/*
3841541Srgrimes	 * Search a new directory.
3851541Srgrimes	 *
3861541Srgrimes	 * The last component of the filename is left accessible via
3871541Srgrimes	 * cnp->cn_nameptr for callers that need the name. Callers needing
3881541Srgrimes	 * the name set the SAVENAME flag. When done, they assume
3891541Srgrimes	 * responsibility for freeing the pathname buffer.
3901541Srgrimes	 */
3911541Srgrimes	cnp->cn_consume = 0;
3921541Srgrimes	for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
39351906Sphk		continue;
3941541Srgrimes	cnp->cn_namelen = cp - cnp->cn_nameptr;
3951541Srgrimes	if (cnp->cn_namelen > NAME_MAX) {
3961541Srgrimes		error = ENAMETOOLONG;
3971541Srgrimes		goto bad;
3981541Srgrimes	}
3991541Srgrimes#ifdef NAMEI_DIAGNOSTIC
4001541Srgrimes	{ char c = *cp;
4011541Srgrimes	*cp = '\0';
4021541Srgrimes	printf("{%s}: ", cnp->cn_nameptr);
4031541Srgrimes	*cp = c; }
4041541Srgrimes#endif
4051541Srgrimes	ndp->ni_pathlen -= cnp->cn_namelen;
4061541Srgrimes	ndp->ni_next = cp;
4079804Sbde
4089804Sbde	/*
4099804Sbde	 * Replace multiple slashes by a single slash and trailing slashes
4109804Sbde	 * by a null.  This must be done before VOP_LOOKUP() because some
4119804Sbde	 * fs's don't know about trailing slashes.  Remember if there were
4129804Sbde	 * trailing slashes to handle symlinks, existing non-directories
4139804Sbde	 * and non-existing files that won't be directories specially later.
4149804Sbde	 */
4159804Sbde	trailing_slash = 0;
4169804Sbde	while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) {
4179804Sbde		cp++;
4189804Sbde		ndp->ni_pathlen--;
4199804Sbde		if (*cp == '\0') {
4209804Sbde			trailing_slash = 1;
4219804Sbde			*ndp->ni_next = '\0';	/* XXX for direnter() ... */
4229804Sbde		}
4239804Sbde	}
4249804Sbde	ndp->ni_next = cp;
4259804Sbde
4261541Srgrimes	cnp->cn_flags |= MAKEENTRY;
4271541Srgrimes	if (*cp == '\0' && docache == 0)
4281541Srgrimes		cnp->cn_flags &= ~MAKEENTRY;
4291541Srgrimes	if (cnp->cn_namelen == 2 &&
4301541Srgrimes	    cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
4311541Srgrimes		cnp->cn_flags |= ISDOTDOT;
4321541Srgrimes	else
4331541Srgrimes		cnp->cn_flags &= ~ISDOTDOT;
4341541Srgrimes	if (*ndp->ni_next == 0)
4351541Srgrimes		cnp->cn_flags |= ISLASTCN;
4361541Srgrimes	else
4371541Srgrimes		cnp->cn_flags &= ~ISLASTCN;
4381541Srgrimes
4391541Srgrimes
4401541Srgrimes	/*
4411541Srgrimes	 * Check for degenerate name (e.g. / or "")
4421541Srgrimes	 * which is a way of talking about a directory,
4431541Srgrimes	 * e.g. like "/." or ".".
4441541Srgrimes	 */
4451541Srgrimes	if (cnp->cn_nameptr[0] == '\0') {
44622521Sdyson		if (dp->v_type != VDIR) {
44722521Sdyson			error = ENOTDIR;
44822521Sdyson			goto bad;
44922521Sdyson		}
4501541Srgrimes		if (cnp->cn_nameiop != LOOKUP) {
4511541Srgrimes			error = EISDIR;
4521541Srgrimes			goto bad;
4531541Srgrimes		}
4541541Srgrimes		if (wantparent) {
4551541Srgrimes			ndp->ni_dvp = dp;
4561541Srgrimes			VREF(dp);
4571541Srgrimes		}
4581541Srgrimes		ndp->ni_vp = dp;
4591541Srgrimes		if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF)))
46083366Sjulian			VOP_UNLOCK(dp, 0, td);
46154655Seivind		/* XXX This should probably move to the top of function. */
4621541Srgrimes		if (cnp->cn_flags & SAVESTART)
4631541Srgrimes			panic("lookup: SAVESTART");
464140714Sjeff		goto success;
4651541Srgrimes	}
4661541Srgrimes
4671541Srgrimes	/*
4681541Srgrimes	 * Handle "..": two special cases.
4691541Srgrimes	 * 1. If at root directory (e.g. after chroot)
4701541Srgrimes	 *    or at absolute root directory
4711541Srgrimes	 *    then ignore it so can't get out.
4721541Srgrimes	 * 2. If this vnode is the root of a mounted
4731541Srgrimes	 *    filesystem, then replace it with the
4741541Srgrimes	 *    vnode which was mounted on so we take the
47596755Strhodes	 *    .. in the other filesystem.
47651649Sphk	 * 3. If the vnode is the top directory of
47751649Sphk	 *    the jail or chroot, don't let them out.
4781541Srgrimes	 */
4791541Srgrimes	if (cnp->cn_flags & ISDOTDOT) {
4801541Srgrimes		for (;;) {
48151649Sphk			if (dp == ndp->ni_rootdir ||
48251649Sphk			    dp == ndp->ni_topdir ||
48351649Sphk			    dp == rootvnode) {
4841541Srgrimes				ndp->ni_dvp = dp;
4851541Srgrimes				ndp->ni_vp = dp;
4861541Srgrimes				VREF(dp);
4871541Srgrimes				goto nextname;
4881541Srgrimes			}
489101308Sjeff			if ((dp->v_vflag & VV_ROOT) == 0 ||
4901541Srgrimes			    (cnp->cn_flags & NOCROSSMOUNT))
4911541Srgrimes				break;
49269405Salfred			if (dp->v_mount == NULL) {	/* forced unmount */
49369405Salfred				error = EBADF;
49469405Salfred				goto bad;
49569405Salfred			}
4961541Srgrimes			tdp = dp;
497144833Sjeff			dp = dp->v_mount->mnt_vnodecovered;
498140714Sjeff			tvfslocked = vfslocked;
499144833Sjeff			vfslocked = VFS_LOCK_GIANT(dp->v_mount);
500144833Sjeff			VREF(dp);
5011541Srgrimes			vput(tdp);
502140714Sjeff			VFS_UNLOCK_GIANT(tvfslocked);
503144286Sjeff			vn_lock(dp, cnp->cn_lkflags | LK_RETRY, td);
5041541Srgrimes		}
5051541Srgrimes	}
5061541Srgrimes
5071541Srgrimes	/*
5081541Srgrimes	 * We now have a segment name to search for, and a directory to search.
5091541Srgrimes	 */
5101541Srgrimesunionlookup:
511101127Srwatson#ifdef MAC
512105479Srwatson	if ((cnp->cn_flags & NOMACCHECK) == 0) {
513105479Srwatson		error = mac_check_vnode_lookup(td->td_ucred, dp, cnp);
514105479Srwatson		if (error)
515105479Srwatson			goto bad;
516105479Srwatson	}
517101127Srwatson#endif
5181541Srgrimes	ndp->ni_dvp = dp;
51922521Sdyson	ndp->ni_vp = NULL;
52024624Sdfr	ASSERT_VOP_LOCKED(dp, "lookup");
521144286Sjeff	/*
522144286Sjeff	 * If we have a shared lock we may need to upgrade the lock for the
523144286Sjeff	 * last operation.
524144286Sjeff	 */
525144286Sjeff	if (VOP_ISLOCKED(dp, td) == LK_SHARED &&
526144286Sjeff	    (cnp->cn_flags & ISLASTCN) && (cnp->cn_flags & LOCKPARENT))
527144286Sjeff		vn_lock(dp, LK_UPGRADE|LK_RETRY, td);
528144286Sjeff	/*
529144286Sjeff	 * If we're looking up the last component and we need an exclusive
530144286Sjeff	 * lock, adjust our lkflags.
531144286Sjeff	 */
532144286Sjeff	if ((cnp->cn_flags & (ISLASTCN|LOCKSHARED|LOCKLEAF)) ==
533144286Sjeff	    (ISLASTCN|LOCKLEAF))
534144286Sjeff		cnp->cn_lkflags = LK_EXCLUSIVE;
535138345Sphk#ifdef NAMEI_DIAGNOSTIC
536138345Sphk	vprint("lookup in", dp);
537138345Sphk#endif
53843301Sdillon	if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
53942408Seivind		KASSERT(ndp->ni_vp == NULL, ("leaf should be empty"));
5401541Srgrimes#ifdef NAMEI_DIAGNOSTIC
5411541Srgrimes		printf("not found\n");
5421541Srgrimes#endif
5431541Srgrimes		if ((error == ENOENT) &&
544101308Sjeff		    (dp->v_vflag & VV_ROOT) && (dp->v_mount != NULL) &&
5451541Srgrimes		    (dp->v_mount->mnt_flag & MNT_UNION)) {
5461541Srgrimes			tdp = dp;
547144833Sjeff			dp = dp->v_mount->mnt_vnodecovered;
548140714Sjeff			tvfslocked = vfslocked;
549144833Sjeff			vfslocked = VFS_LOCK_GIANT(dp->v_mount);
550144833Sjeff			VREF(dp);
551144203Sjeff			vput(tdp);
552140714Sjeff			VFS_UNLOCK_GIANT(tvfslocked);
553144286Sjeff			vn_lock(dp, cnp->cn_lkflags | LK_RETRY, td);
5541541Srgrimes			goto unionlookup;
5551541Srgrimes		}
5561541Srgrimes
5571541Srgrimes		if (error != EJUSTRETURN)
5581541Srgrimes			goto bad;
5591541Srgrimes		/*
5601541Srgrimes		 * If creating and at end of pathname, then can consider
5611541Srgrimes		 * allowing file to be created.
5621541Srgrimes		 */
56311644Sdg		if (rdonly) {
5641541Srgrimes			error = EROFS;
5651541Srgrimes			goto bad;
5661541Srgrimes		}
5679804Sbde		if (*cp == '\0' && trailing_slash &&
5689804Sbde		     !(cnp->cn_flags & WILLBEDIR)) {
5699804Sbde			error = ENOENT;
5709804Sbde			goto bad;
5719804Sbde		}
572144203Sjeff		if ((cnp->cn_flags & LOCKPARENT) == 0)
573144203Sjeff			VOP_UNLOCK(dp, 0, td);
5741541Srgrimes		/*
575144203Sjeff		 * This is a temporary assert to make sure I know what the
576144203Sjeff		 * behavior here was.
577144203Sjeff		 */
578144203Sjeff		KASSERT((cnp->cn_flags & (WANTPARENT|LOCKPARENT)) != 0,
579144203Sjeff		   ("lookup: Unhandled case."));
580144203Sjeff		/*
5811541Srgrimes		 * We return with ni_vp NULL to indicate that the entry
5821541Srgrimes		 * doesn't currently exist, leaving a pointer to the
5831541Srgrimes		 * (possibly locked) directory inode in ndp->ni_dvp.
5841541Srgrimes		 */
5851541Srgrimes		if (cnp->cn_flags & SAVESTART) {
5861541Srgrimes			ndp->ni_startdir = ndp->ni_dvp;
5871541Srgrimes			VREF(ndp->ni_startdir);
5881541Srgrimes		}
589140714Sjeff		goto success;
5901541Srgrimes	}
5911541Srgrimes#ifdef NAMEI_DIAGNOSTIC
5921541Srgrimes	printf("found\n");
5931541Srgrimes#endif
594144203Sjeff	/*
595144833Sjeff	 * In the DOTDOT case dp is unlocked, we relock it here even if we
596144833Sjeff	 * may not need it to simplify the code below.
597144203Sjeff	 */
598144833Sjeff	if (cnp->cn_flags & ISDOTDOT)
599144833Sjeff		vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
6001541Srgrimes	/*
6011541Srgrimes	 * Take into account any additional components consumed by
6021541Srgrimes	 * the underlying filesystem.
6031541Srgrimes	 */
6041541Srgrimes	if (cnp->cn_consume > 0) {
6051541Srgrimes		cnp->cn_nameptr += cnp->cn_consume;
6061541Srgrimes		ndp->ni_next += cnp->cn_consume;
6071541Srgrimes		ndp->ni_pathlen -= cnp->cn_consume;
6081541Srgrimes		cnp->cn_consume = 0;
6091541Srgrimes	}
6101541Srgrimes
6111541Srgrimes	dp = ndp->ni_vp;
6121541Srgrimes
6131541Srgrimes	/*
6141541Srgrimes	 * Check to see if the vnode has been mounted on;
61596755Strhodes	 * if so find the root of the mounted filesystem.
6161541Srgrimes	 */
6171541Srgrimes	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
6181541Srgrimes	       (cnp->cn_flags & NOCROSSMOUNT) == 0) {
619144833Sjeff		KASSERT(dp != ndp->ni_dvp, ("XXX"));
62083366Sjulian		if (vfs_busy(mp, 0, 0, td))
6211541Srgrimes			continue;
622144833Sjeff		vput(dp);
623140714Sjeff		tvfslocked = VFS_LOCK_GIANT(mp);
624144833Sjeff		VFS_UNLOCK_GIANT(vfslocked);
625144833Sjeff		vfslocked = tvfslocked;
626144286Sjeff		error = VFS_ROOT(mp, cnp->cn_lkflags, &tdp, td);
62783366Sjulian		vfs_unbusy(mp, td);
62865805Sbp		if (error) {
62965805Sbp			dpunlocked = 1;
6301541Srgrimes			goto bad2;
63165805Sbp		}
6321541Srgrimes		ndp->ni_vp = dp = tdp;
6331541Srgrimes	}
6341541Srgrimes
63510219Sdfr	/*
63610219Sdfr	 * Check for symbolic link
63710219Sdfr	 */
63810219Sdfr	if ((dp->v_type == VLNK) &&
63910219Sdfr	    ((cnp->cn_flags & FOLLOW) || trailing_slash ||
64010219Sdfr	     *ndp->ni_next == '/')) {
64110219Sdfr		cnp->cn_flags |= ISSYMLINK;
64269405Salfred		if (dp->v_mount == NULL) {
64369405Salfred			/* We can't know whether the directory was mounted with
64469405Salfred			 * NOSYMFOLLOW, so we can't follow safely. */
64569405Salfred			error = EBADF;
64669405Salfred			goto bad2;
64769405Salfred		}
64835105Swosch		if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) {
64935105Swosch			error = EACCES;
65035105Swosch			goto bad2;
65135105Swosch		}
652144833Sjeff		/*
653144833Sjeff		 * Symlink code always expects an unlocked dvp.
654144833Sjeff		 */
655144833Sjeff		if (ndp->ni_dvp != ndp->ni_vp)
656144833Sjeff			VOP_UNLOCK(ndp->ni_dvp, 0, td);
657140714Sjeff		goto success;
65810219Sdfr	}
65910219Sdfr
66010219Sdfr	/*
66110219Sdfr	 * Check for bogus trailing slashes.
66210219Sdfr	 */
66310219Sdfr	if (trailing_slash && dp->v_type != VDIR) {
66410219Sdfr		error = ENOTDIR;
66510219Sdfr		goto bad2;
66610219Sdfr	}
66710219Sdfr
6681541Srgrimesnextname:
6691541Srgrimes	/*
6701541Srgrimes	 * Not a symbolic link.  If more pathname,
6711541Srgrimes	 * continue at next component, else return.
6721541Srgrimes	 */
673144203Sjeff	KASSERT((cnp->cn_flags & ISLASTCN) || *ndp->ni_next == '/',
674144203Sjeff	    ("lookup: invalid path state."));
6751541Srgrimes	if (*ndp->ni_next == '/') {
6761541Srgrimes		cnp->cn_nameptr = ndp->ni_next;
6771541Srgrimes		while (*cnp->cn_nameptr == '/') {
6781541Srgrimes			cnp->cn_nameptr++;
6791541Srgrimes			ndp->ni_pathlen--;
6801541Srgrimes		}
681144833Sjeff		if (ndp->ni_dvp != dp)
682144833Sjeff			vput(ndp->ni_dvp);
683144833Sjeff		else
684144833Sjeff			vrele(ndp->ni_dvp);
6851541Srgrimes		goto dirloop;
6861541Srgrimes	}
6871541Srgrimes	/*
68896755Strhodes	 * Disallow directory write attempts on read-only filesystems.
6891541Srgrimes	 */
69011644Sdg	if (rdonly &&
69111644Sdg	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
69211644Sdg		error = EROFS;
69311644Sdg		goto bad2;
6941541Srgrimes	}
6951541Srgrimes	if (cnp->cn_flags & SAVESTART) {
6961541Srgrimes		ndp->ni_startdir = ndp->ni_dvp;
6971541Srgrimes		VREF(ndp->ni_startdir);
6981541Srgrimes	}
699144833Sjeff	if (!wantparent) {
700144833Sjeff		if (ndp->ni_dvp != dp)
701144833Sjeff			vput(ndp->ni_dvp);
702144833Sjeff		else
703144833Sjeff			vrele(ndp->ni_dvp);
704144833Sjeff	} else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp)
705144833Sjeff		VOP_UNLOCK(ndp->ni_dvp, 0, td);
70632071Sdyson
7071541Srgrimes	if ((cnp->cn_flags & LOCKLEAF) == 0)
70883366Sjulian		VOP_UNLOCK(dp, 0, td);
709140714Sjeffsuccess:
710140714Sjeff	if (vfslocked)
711140714Sjeff		ndp->ni_cnd.cn_flags |= GIANTHELD;
7121541Srgrimes	return (0);
7131541Srgrimes
7141541Srgrimesbad2:
715144833Sjeff	if (dp != ndp->ni_dvp)
716144203Sjeff		vput(ndp->ni_dvp);
717144203Sjeff	else
718144203Sjeff		vrele(ndp->ni_dvp);
7191541Srgrimesbad:
720144833Sjeff	if (!dpunlocked)
72165805Sbp		vput(dp);
722140714Sjeff	VFS_UNLOCK_GIANT(vfslocked);
723140714Sjeff	ndp->ni_cnd.cn_flags &= ~GIANTHELD;
7241541Srgrimes	ndp->ni_vp = NULL;
7251541Srgrimes	return (error);
7261541Srgrimes}
7271541Srgrimes
7283148Sphk/*
7293148Sphk * relookup - lookup a path name component
7303148Sphk *    Used by lookup to re-aquire things.
7313148Sphk */
7323148Sphkint
7333148Sphkrelookup(dvp, vpp, cnp)
7343148Sphk	struct vnode *dvp, **vpp;
7353148Sphk	struct componentname *cnp;
7363148Sphk{
73783366Sjulian	struct thread *td = cnp->cn_thread;
73822521Sdyson	struct vnode *dp = 0;		/* the directory we are searching */
7393148Sphk	int wantparent;			/* 1 => wantparent or lockparent flag */
7403148Sphk	int rdonly;			/* lookup read-only flag bit */
7413148Sphk	int error = 0;
7421541Srgrimes
743144203Sjeff	KASSERT(cnp->cn_flags & ISLASTCN,
744144203Sjeff	    ("relookup: Not given last component."));
7453148Sphk	/*
7463148Sphk	 * Setup: break out flag bits into variables.
7473148Sphk	 */
7483148Sphk	wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
7493148Sphk	rdonly = cnp->cn_flags & RDONLY;
7503148Sphk	cnp->cn_flags &= ~ISSYMLINK;
7513148Sphk	dp = dvp;
752144286Sjeff	cnp->cn_lkflags = LK_EXCLUSIVE;
75383366Sjulian	vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
7543148Sphk
7553148Sphk	/*
7563148Sphk	 * Search a new directory.
7573148Sphk	 *
7583148Sphk	 * The last component of the filename is left accessible via
7593148Sphk	 * cnp->cn_nameptr for callers that need the name. Callers needing
7603148Sphk	 * the name set the SAVENAME flag. When done, they assume
7613148Sphk	 * responsibility for freeing the pathname buffer.
7623148Sphk	 */
7633148Sphk#ifdef NAMEI_DIAGNOSTIC
7643148Sphk	printf("{%s}: ", cnp->cn_nameptr);
7653148Sphk#endif
7663148Sphk
7673148Sphk	/*
7683148Sphk	 * Check for degenerate name (e.g. / or "")
7693148Sphk	 * which is a way of talking about a directory,
7703148Sphk	 * e.g. like "/." or ".".
7713148Sphk	 */
7723148Sphk	if (cnp->cn_nameptr[0] == '\0') {
7733148Sphk		if (cnp->cn_nameiop != LOOKUP || wantparent) {
7743148Sphk			error = EISDIR;
7753148Sphk			goto bad;
7763148Sphk		}
7773148Sphk		if (dp->v_type != VDIR) {
7783148Sphk			error = ENOTDIR;
7793148Sphk			goto bad;
7803148Sphk		}
7813148Sphk		if (!(cnp->cn_flags & LOCKLEAF))
78283366Sjulian			VOP_UNLOCK(dp, 0, td);
7833148Sphk		*vpp = dp;
78454655Seivind		/* XXX This should probably move to the top of function. */
7853148Sphk		if (cnp->cn_flags & SAVESTART)
7863148Sphk			panic("lookup: SAVESTART");
7873148Sphk		return (0);
7883148Sphk	}
7893148Sphk
7903148Sphk	if (cnp->cn_flags & ISDOTDOT)
7913148Sphk		panic ("relookup: lookup on dot-dot");
7923148Sphk
7933148Sphk	/*
7943148Sphk	 * We now have a segment name to search for, and a directory to search.
7953148Sphk	 */
796138345Sphk#ifdef NAMEI_DIAGNOSTIC
797138345Sphk	vprint("search in:", dp);
798138345Sphk#endif
79943311Sdillon	if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
80042408Seivind		KASSERT(*vpp == NULL, ("leaf should be empty"));
8013148Sphk		if (error != EJUSTRETURN)
8023148Sphk			goto bad;
8033148Sphk		/*
8043148Sphk		 * If creating and at end of pathname, then can consider
8053148Sphk		 * allowing file to be created.
8063148Sphk		 */
80711644Sdg		if (rdonly) {
8083148Sphk			error = EROFS;
8093148Sphk			goto bad;
8103148Sphk		}
8113148Sphk		/* ASSERT(dvp == ndp->ni_startdir) */
8123148Sphk		if (cnp->cn_flags & SAVESTART)
8133148Sphk			VREF(dvp);
814144203Sjeff		if ((cnp->cn_flags & LOCKPARENT) == 0)
815144203Sjeff			VOP_UNLOCK(dp, 0, td);
8163148Sphk		/*
817144203Sjeff		 * This is a temporary assert to make sure I know what the
818144203Sjeff		 * behavior here was.
819144203Sjeff		 */
820144203Sjeff		KASSERT((cnp->cn_flags & (WANTPARENT|LOCKPARENT)) != 0,
821144203Sjeff		   ("relookup: Unhandled case."));
822144203Sjeff		/*
8233148Sphk		 * We return with ni_vp NULL to indicate that the entry
8243148Sphk		 * doesn't currently exist, leaving a pointer to the
8253148Sphk		 * (possibly locked) directory inode in ndp->ni_dvp.
8263148Sphk		 */
8273148Sphk		return (0);
8283148Sphk	}
829144203Sjeff	/*
830144203Sjeff	 * In the DOTDOT case dp is unlocked, we may have to relock it if
831144203Sjeff	 * LOCKPARENT is set.  Otherwise, unlock the parent.
832144203Sjeff	 */
833144203Sjeff	if ((cnp->cn_flags & (ISDOTDOT | LOCKPARENT)) ==
834144203Sjeff	    (ISDOTDOT | LOCKPARENT))
835144203Sjeff		vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
836144203Sjeff	else if ((cnp->cn_flags & (ISDOTDOT | LOCKPARENT)) == 0 && dp != *vpp)
837144203Sjeff		VOP_UNLOCK(dp, 0, td);
8383148Sphk	dp = *vpp;
8393148Sphk
8403148Sphk	/*
8413148Sphk	 * Check for symbolic link
8423148Sphk	 */
84342408Seivind	KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW),
84442453Seivind	    ("relookup: symlink found.\n"));
8453148Sphk
8463148Sphk	/*
84796755Strhodes	 * Disallow directory write attempts on read-only filesystems.
8483148Sphk	 */
84911644Sdg	if (rdonly &&
85011644Sdg	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
85111644Sdg		error = EROFS;
85211644Sdg		goto bad2;
8533148Sphk	}
8543148Sphk	/* ASSERT(dvp == ndp->ni_startdir) */
8553148Sphk	if (cnp->cn_flags & SAVESTART)
8563148Sphk		VREF(dvp);
85722521Sdyson
8583148Sphk	if (!wantparent)
8593148Sphk		vrele(dvp);
86032071Sdyson
8613148Sphk	if ((cnp->cn_flags & LOCKLEAF) == 0)
86283366Sjulian		VOP_UNLOCK(dp, 0, td);
8633148Sphk	return (0);
8643148Sphk
8653148Sphkbad2:
866144203Sjeff	if (cnp->cn_flags & LOCKPARENT)
86783366Sjulian		VOP_UNLOCK(dvp, 0, td);
8683148Sphk	vrele(dvp);
8693148Sphkbad:
8703148Sphk	vput(dp);
8713148Sphk	*vpp = NULL;
8723148Sphk	return (error);
8733148Sphk}
874141471Sjhb
875141471Sjhb/*
876144661Sjeff * Free data allocated by namei(); see namei(9) for details.
877144661Sjeff */
878144661Sjeffvoid
879144661SjeffNDFREE(ndp, flags)
880144661Sjeff     struct nameidata *ndp;
881144661Sjeff     const u_int flags;
882144661Sjeff{
883144833Sjeff	int unlock_dvp;
884144833Sjeff	int unlock_vp;
885144661Sjeff
886144833Sjeff	unlock_dvp = 0;
887144833Sjeff	unlock_vp = 0;
888144833Sjeff
889144661Sjeff	if (!(flags & NDF_NO_FREE_PNBUF) &&
890144661Sjeff	    (ndp->ni_cnd.cn_flags & HASBUF)) {
891144661Sjeff		uma_zfree(namei_zone, ndp->ni_cnd.cn_pnbuf);
892144661Sjeff		ndp->ni_cnd.cn_flags &= ~HASBUF;
893144661Sjeff	}
894144833Sjeff	if (!(flags & NDF_NO_VP_UNLOCK) &&
895144833Sjeff	    (ndp->ni_cnd.cn_flags & LOCKLEAF) && ndp->ni_vp)
896144833Sjeff		unlock_vp = 1;
897144833Sjeff	if (!(flags & NDF_NO_VP_RELE) && ndp->ni_vp) {
898144833Sjeff		if (unlock_vp) {
899144833Sjeff			vput(ndp->ni_vp);
900144833Sjeff			unlock_vp = 0;
901144833Sjeff		} else
902144833Sjeff			vrele(ndp->ni_vp);
903144833Sjeff		ndp->ni_vp = NULL;
904144833Sjeff	}
905144833Sjeff	if (unlock_vp)
906144833Sjeff		VOP_UNLOCK(ndp->ni_vp, 0, ndp->ni_cnd.cn_thread);
907144661Sjeff	if (!(flags & NDF_NO_DVP_UNLOCK) &&
908144661Sjeff	    (ndp->ni_cnd.cn_flags & LOCKPARENT) &&
909144661Sjeff	    ndp->ni_dvp != ndp->ni_vp)
910144833Sjeff		unlock_dvp = 1;
911144661Sjeff	if (!(flags & NDF_NO_DVP_RELE) &&
912144661Sjeff	    (ndp->ni_cnd.cn_flags & (LOCKPARENT|WANTPARENT))) {
913144833Sjeff		if (unlock_dvp) {
914144833Sjeff			vput(ndp->ni_dvp);
915144833Sjeff			unlock_dvp = 0;
916144833Sjeff		} else
917144833Sjeff			vrele(ndp->ni_dvp);
918144661Sjeff		ndp->ni_dvp = NULL;
919144661Sjeff	}
920144833Sjeff	if (unlock_dvp)
921144833Sjeff		VOP_UNLOCK(ndp->ni_dvp, 0, ndp->ni_cnd.cn_thread);
922144661Sjeff	if (!(flags & NDF_NO_STARTDIR_RELE) &&
923144661Sjeff	    (ndp->ni_cnd.cn_flags & SAVESTART)) {
924144661Sjeff		vrele(ndp->ni_startdir);
925144661Sjeff		ndp->ni_startdir = NULL;
926144661Sjeff	}
927144661Sjeff}
928144661Sjeff
929144661Sjeff/*
930141471Sjhb * Determine if there is a suitable alternate filename under the specified
931141471Sjhb * prefix for the specified path.  If the create flag is set, then the
932141471Sjhb * alternate prefix will be used so long as the parent directory exists.
933141471Sjhb * This is used by the various compatiblity ABIs so that Linux binaries prefer
934141471Sjhb * files under /compat/linux for example.  The chosen path (whether under
935141471Sjhb * the prefix or under /) is returned in a kernel malloc'd buffer pointed
936141471Sjhb * to by pathbuf.  The caller is responsible for free'ing the buffer from
937141471Sjhb * the M_TEMP bucket if one is returned.
938141471Sjhb */
939141471Sjhbint
940141471Sjhbkern_alternate_path(struct thread *td, const char *prefix, char *path,
941141471Sjhb    enum uio_seg pathseg, char **pathbuf, int create)
942141471Sjhb{
943141471Sjhb	struct nameidata nd, ndroot;
944141471Sjhb	char *ptr, *buf, *cp;
945141471Sjhb	size_t len, sz;
946141471Sjhb	int error;
947141471Sjhb
948141471Sjhb	buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
949141471Sjhb	*pathbuf = buf;
950141471Sjhb
951141471Sjhb	/* Copy the prefix into the new pathname as a starting point. */
952141471Sjhb	len = strlcpy(buf, prefix, MAXPATHLEN);
953141471Sjhb	if (len >= MAXPATHLEN) {
954141471Sjhb		*pathbuf = NULL;
955141471Sjhb		free(buf, M_TEMP);
956141471Sjhb		return (EINVAL);
957141471Sjhb	}
958141471Sjhb	sz = MAXPATHLEN - len;
959141471Sjhb	ptr = buf + len;
960141471Sjhb
961141471Sjhb	/* Append the filename to the prefix. */
962141471Sjhb	if (pathseg == UIO_SYSSPACE)
963141471Sjhb		error = copystr(path, ptr, sz, &len);
964141471Sjhb	else
965141471Sjhb		error = copyinstr(path, ptr, sz, &len);
966141471Sjhb
967141471Sjhb	if (error) {
968141471Sjhb		*pathbuf = NULL;
969141471Sjhb		free(buf, M_TEMP);
970141471Sjhb		return (error);
971141471Sjhb	}
972141471Sjhb
973141471Sjhb	/* Only use a prefix with absolute pathnames. */
974141471Sjhb	if (*ptr != '/') {
975141471Sjhb		error = EINVAL;
976141471Sjhb		goto keeporig;
977141471Sjhb	}
978141471Sjhb
979141471Sjhb	/* XXX: VFS_LOCK_GIANT? */
980141471Sjhb	mtx_lock(&Giant);
981141471Sjhb
982141471Sjhb	/*
983141471Sjhb	 * We know that there is a / somewhere in this pathname.
984141471Sjhb	 * Search backwards for it, to find the file's parent dir
985141471Sjhb	 * to see if it exists in the alternate tree. If it does,
986141471Sjhb	 * and we want to create a file (cflag is set). We don't
987141471Sjhb	 * need to worry about the root comparison in this case.
988141471Sjhb	 */
989141471Sjhb
990141471Sjhb	if (create) {
991141471Sjhb		for (cp = &ptr[len] - 1; *cp != '/'; cp--);
992141471Sjhb		*cp = '\0';
993141471Sjhb
994141471Sjhb		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
995141471Sjhb		error = namei(&nd);
996141471Sjhb		*cp = '/';
997141471Sjhb		if (error != 0)
998141471Sjhb			goto nd_failed;
999141471Sjhb	} else {
1000141471Sjhb		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
1001141471Sjhb
1002141471Sjhb		error = namei(&nd);
1003141471Sjhb		if (error != 0)
1004141471Sjhb			goto nd_failed;
1005141471Sjhb
1006141471Sjhb		/*
1007141471Sjhb		 * We now compare the vnode of the prefix to the one
1008141471Sjhb		 * vnode asked. If they resolve to be the same, then we
1009141471Sjhb		 * ignore the match so that the real root gets used.
1010141471Sjhb		 * This avoids the problem of traversing "../.." to find the
1011141471Sjhb		 * root directory and never finding it, because "/" resolves
1012141471Sjhb		 * to the emulation root directory. This is expensive :-(
1013141471Sjhb		 */
1014141471Sjhb		NDINIT(&ndroot, LOOKUP, FOLLOW, UIO_SYSSPACE, prefix, td);
1015141471Sjhb
1016141471Sjhb		/* We shouldn't ever get an error from this namei(). */
1017141471Sjhb		error = namei(&ndroot);
1018141471Sjhb		if (error == 0) {
1019141471Sjhb			if (nd.ni_vp == ndroot.ni_vp)
1020141471Sjhb				error = ENOENT;
1021141471Sjhb
1022141471Sjhb			NDFREE(&ndroot, NDF_ONLY_PNBUF);
1023141471Sjhb			vrele(ndroot.ni_vp);
1024141471Sjhb		}
1025141471Sjhb	}
1026141471Sjhb
1027141471Sjhb	NDFREE(&nd, NDF_ONLY_PNBUF);
1028141471Sjhb	vrele(nd.ni_vp);
1029141471Sjhb
1030141471Sjhbnd_failed:
1031141471Sjhb	/* XXX: VFS_UNLOCK_GIANT? */
1032141471Sjhb	mtx_unlock(&Giant);
1033141471Sjhb
1034141471Sjhbkeeporig:
1035141471Sjhb	/* If there was an error, use the original path name. */
1036141471Sjhb	if (error)
1037141471Sjhb		bcopy(ptr, buf, len);
1038141471Sjhb	return (error);
1039141471Sjhb}
1040