vfs_lookup.c revision 141471
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 141471 2005-02-07 18:44:55Z jhb $"); 39116182Sobrien 4013203Swollman#include "opt_ktrace.h" 41101127Srwatson#include "opt_mac.h" 4213203Swollman 431541Srgrimes#include <sys/param.h> 442112Swollman#include <sys/systm.h> 4569664Speter#include <sys/kernel.h> 4676166Smarkm#include <sys/lock.h> 47101127Srwatson#include <sys/mac.h> 4889316Salfred#include <sys/mutex.h> 491541Srgrimes#include <sys/namei.h> 501541Srgrimes#include <sys/vnode.h> 511541Srgrimes#include <sys/mount.h> 521541Srgrimes#include <sys/filedesc.h> 531541Srgrimes#include <sys/proc.h> 54141471Sjhb#include <sys/syscallsubr.h> 551541Srgrimes#ifdef KTRACE 561541Srgrimes#include <sys/ktrace.h> 571541Srgrimes#endif 581541Srgrimes 5992751Sjeff#include <vm/uma.h> 6032011Sbde 61138345Sphk#define NAMEI_DIAGNOSTIC 1 62138345Sphk#undef NAMEI_DIAGNOSTIC 63138345Sphk 641541Srgrimes/* 6569664Speter * Allocation zone for namei 6669664Speter */ 6792751Sjeffuma_zone_t namei_zone; 6869664Speter 6969664Speterstatic void 7069664Speternameiinit(void *dummy __unused) 7169664Speter{ 7292654Sjeff namei_zone = uma_zcreate("NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL, 7392654Sjeff UMA_ALIGN_PTR, 0); 7469664Speter 7569664Speter} 7669664SpeterSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL) 7769664Speter 7869664Speter/* 791541Srgrimes * Convert a pathname into a pointer to a locked inode. 801541Srgrimes * 811541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed 821541Srgrimes * when they occur at the end of the name translation process. 831541Srgrimes * Symbolic links are always followed for all other pathname 841541Srgrimes * components other than the last. 851541Srgrimes * 861541Srgrimes * The segflg defines whether the name is to be copied from user 871541Srgrimes * space or kernel space. 881541Srgrimes * 891541Srgrimes * Overall outline of namei: 901541Srgrimes * 911541Srgrimes * copy in name 921541Srgrimes * get starting directory 931541Srgrimes * while (!done && !error) { 941541Srgrimes * call lookup to search path. 951541Srgrimes * if symbolic link, massage name in buffer and continue 961541Srgrimes * } 971541Srgrimes */ 981541Srgrimesint 991541Srgrimesnamei(ndp) 1001541Srgrimes register struct nameidata *ndp; 1011541Srgrimes{ 1021541Srgrimes register struct filedesc *fdp; /* pointer to file descriptor state */ 1031541Srgrimes register char *cp; /* pointer into pathname argument */ 1041541Srgrimes register struct vnode *dp; /* the directory we are searching */ 1051541Srgrimes struct iovec aiov; /* uio for reading symbolic links */ 1061541Srgrimes struct uio auio; 1071541Srgrimes int error, linklen; 1081541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 10983366Sjulian struct thread *td = cnp->cn_thread; 11083366Sjulian struct proc *p = td->td_proc; 111140714Sjeff struct mount *mp; 112140714Sjeff int vfslocked; 1131541Srgrimes 11491419Sjhb ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred; 11583366Sjulian KASSERT(cnp->cn_cred && p, ("namei: bad cred/proc")); 11642408Seivind KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0, 11742453Seivind ("namei: nameiop contaminated with flags")); 11842408Seivind KASSERT((cnp->cn_flags & OPMASK) == 0, 11942453Seivind ("namei: flags contaminated with nameiops")); 12083366Sjulian fdp = p->p_fd; 1211541Srgrimes 1221541Srgrimes /* 1231541Srgrimes * Get a buffer for the name to be translated, and copy the 1241541Srgrimes * name into the buffer. 1251541Srgrimes */ 1261541Srgrimes if ((cnp->cn_flags & HASBUF) == 0) 127111119Simp cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 1281541Srgrimes if (ndp->ni_segflg == UIO_SYSSPACE) 1291541Srgrimes error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 13036735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 1311541Srgrimes else 1321541Srgrimes error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 13336735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 13420069Sbde 13520069Sbde /* 13620069Sbde * Don't allow empty pathnames. 13720069Sbde */ 13820069Sbde if (!error && *cnp->cn_pnbuf == '\0') 13920069Sbde error = ENOENT; 14020069Sbde 1411541Srgrimes if (error) { 14292751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 143100613Srwatson#ifdef DIAGNOSTIC 144100613Srwatson cnp->cn_pnbuf = NULL; 145100613Srwatson cnp->cn_nameptr = NULL; 146100613Srwatson#endif 1471541Srgrimes ndp->ni_vp = NULL; 1481541Srgrimes return (error); 1491541Srgrimes } 1501541Srgrimes ndp->ni_loopcnt = 0; 1511541Srgrimes#ifdef KTRACE 15297994Sjhb if (KTRPOINT(td, KTR_NAMEI)) { 15397994Sjhb KASSERT(cnp->cn_thread == curthread, 15497994Sjhb ("namei not using curthread")); 15597994Sjhb ktrnamei(cnp->cn_pnbuf); 15697994Sjhb } 1571541Srgrimes#endif 1581541Srgrimes 1591541Srgrimes /* 1601541Srgrimes * Get starting point for the translation. 1611541Srgrimes */ 16289306Salfred FILEDESC_LOCK(fdp); 16333360Sdyson ndp->ni_rootdir = fdp->fd_rdir; 16451649Sphk ndp->ni_topdir = fdp->fd_jdir; 16533360Sdyson 1661541Srgrimes dp = fdp->fd_cdir; 167140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 1681541Srgrimes VREF(dp); 16989306Salfred FILEDESC_UNLOCK(fdp); 1701541Srgrimes for (;;) { 1711541Srgrimes /* 1721541Srgrimes * Check if root directory should replace current directory. 1731541Srgrimes * Done at start of translation and after symbolic link. 1741541Srgrimes */ 1751541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 1761541Srgrimes if (*(cnp->cn_nameptr) == '/') { 1771541Srgrimes vrele(dp); 178140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 1791541Srgrimes while (*(cnp->cn_nameptr) == '/') { 1801541Srgrimes cnp->cn_nameptr++; 1811541Srgrimes ndp->ni_pathlen--; 1821541Srgrimes } 1831541Srgrimes dp = ndp->ni_rootdir; 184140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 1851541Srgrimes VREF(dp); 1861541Srgrimes } 187140714Sjeff if (vfslocked) 188140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 1891541Srgrimes ndp->ni_startdir = dp; 1903148Sphk error = lookup(ndp); 1913148Sphk if (error) { 19292751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 193100613Srwatson#ifdef DIAGNOSTIC 194100613Srwatson cnp->cn_pnbuf = NULL; 195100613Srwatson cnp->cn_nameptr = NULL; 196100613Srwatson#endif 1971541Srgrimes return (error); 1981541Srgrimes } 199140714Sjeff vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; 200140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 2011541Srgrimes /* 2021541Srgrimes * Check for symbolic link 2031541Srgrimes */ 2041541Srgrimes if ((cnp->cn_flags & ISSYMLINK) == 0) { 205100613Srwatson if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) { 20692751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 207100613Srwatson#ifdef DIAGNOSTIC 208100613Srwatson cnp->cn_pnbuf = NULL; 209100613Srwatson cnp->cn_nameptr = NULL; 210100613Srwatson#endif 211100613Srwatson } else 2121541Srgrimes cnp->cn_flags |= HASBUF; 21332286Sdyson 214140714Sjeff if ((cnp->cn_flags & MPSAFE) == 0) { 215140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 216140714Sjeff } else if (vfslocked) 217140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 2181541Srgrimes return (0); 2191541Srgrimes } 2201541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 22183366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 2221541Srgrimes if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 2231541Srgrimes error = ELOOP; 2241541Srgrimes break; 2251541Srgrimes } 226101127Srwatson#ifdef MAC 227105479Srwatson if ((cnp->cn_flags & NOMACCHECK) == 0) { 228105479Srwatson error = mac_check_vnode_readlink(td->td_ucred, 229105479Srwatson ndp->ni_vp); 230105479Srwatson if (error) 231105479Srwatson break; 232105479Srwatson } 233101127Srwatson#endif 2341541Srgrimes if (ndp->ni_pathlen > 1) 235111119Simp cp = uma_zalloc(namei_zone, M_WAITOK); 2361541Srgrimes else 2371541Srgrimes cp = cnp->cn_pnbuf; 2381541Srgrimes aiov.iov_base = cp; 2391541Srgrimes aiov.iov_len = MAXPATHLEN; 2401541Srgrimes auio.uio_iov = &aiov; 2411541Srgrimes auio.uio_iovcnt = 1; 2421541Srgrimes auio.uio_offset = 0; 2431541Srgrimes auio.uio_rw = UIO_READ; 2441541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 24583366Sjulian auio.uio_td = (struct thread *)0; 2461541Srgrimes auio.uio_resid = MAXPATHLEN; 2473148Sphk error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 2483148Sphk if (error) { 2491541Srgrimes if (ndp->ni_pathlen > 1) 25092751Sjeff uma_zfree(namei_zone, cp); 2511541Srgrimes break; 2521541Srgrimes } 2531541Srgrimes linklen = MAXPATHLEN - auio.uio_resid; 25478692Sdillon if (linklen == 0) { 25578692Sdillon if (ndp->ni_pathlen > 1) 25692751Sjeff uma_zfree(namei_zone, cp); 25778692Sdillon error = ENOENT; 25878692Sdillon break; 25978692Sdillon } 2601541Srgrimes if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 2611541Srgrimes if (ndp->ni_pathlen > 1) 26292751Sjeff uma_zfree(namei_zone, cp); 2631541Srgrimes error = ENAMETOOLONG; 2641541Srgrimes break; 2651541Srgrimes } 2661541Srgrimes if (ndp->ni_pathlen > 1) { 2671541Srgrimes bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 26892751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 2691541Srgrimes cnp->cn_pnbuf = cp; 2701541Srgrimes } else 2711541Srgrimes cnp->cn_pnbuf[linklen] = '\0'; 2721541Srgrimes ndp->ni_pathlen += linklen; 2731541Srgrimes vput(ndp->ni_vp); 2741541Srgrimes dp = ndp->ni_dvp; 2751541Srgrimes } 27692751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 277100613Srwatson#ifdef DIAGNOSTIC 278100613Srwatson cnp->cn_pnbuf = NULL; 279100613Srwatson cnp->cn_nameptr = NULL; 280100613Srwatson#endif 2811541Srgrimes vrele(ndp->ni_dvp); 282140714Sjeff mp = ndp->ni_vp->v_mount; 2831541Srgrimes vput(ndp->ni_vp); 284140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 2851541Srgrimes ndp->ni_vp = NULL; 2861541Srgrimes return (error); 2871541Srgrimes} 2881541Srgrimes 2891541Srgrimes/* 2901541Srgrimes * Search a pathname. 2911541Srgrimes * This is a very central and rather complicated routine. 2921541Srgrimes * 2931541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 2941541Srgrimes * The starting directory is taken from ni_startdir. The pathname is 2951541Srgrimes * descended until done, or a symbolic link is encountered. The variable 2961541Srgrimes * ni_more is clear if the path is completed; it is set to one if a 2971541Srgrimes * symbolic link needing interpretation is encountered. 2981541Srgrimes * 2991541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 3001541Srgrimes * whether the name is to be looked up, created, renamed, or deleted. 3011541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in 3021541Srgrimes * creating, renaming, or deleting a directory entry may be calculated. 3031541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned 3041541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is 3051541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If 3061541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag 3071541Srgrimes * the target is returned locked, otherwise it is returned unlocked. 3081541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not 3091541Srgrimes * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 3108876Srgrimes * 3111541Srgrimes * Overall outline of lookup: 3121541Srgrimes * 3131541Srgrimes * dirloop: 3141541Srgrimes * identify next component of name at ndp->ni_ptr 3151541Srgrimes * handle degenerate case where name is null string 3161541Srgrimes * if .. and crossing mount points and on mounted filesys, find parent 3171541Srgrimes * call VOP_LOOKUP routine for next component name 3181541Srgrimes * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 3191541Srgrimes * component vnode returned in ni_vp (if it exists), locked. 3201541Srgrimes * if result vnode is mounted on and crossing mount points, 3211541Srgrimes * find mounted on vnode 3221541Srgrimes * if more components of name, do next level at dirloop 3231541Srgrimes * return the answer in ni_vp, locked if LOCKLEAF set 3241541Srgrimes * if LOCKPARENT set, return locked parent in ni_dvp 3251541Srgrimes * if WANTPARENT set, return unlocked parent in ni_dvp 3261541Srgrimes */ 3271541Srgrimesint 3281541Srgrimeslookup(ndp) 3291541Srgrimes register struct nameidata *ndp; 3301541Srgrimes{ 3311541Srgrimes register char *cp; /* pointer into pathname argument */ 3321541Srgrimes register struct vnode *dp = 0; /* the directory we are searching */ 3331541Srgrimes struct vnode *tdp; /* saved dp */ 3341541Srgrimes struct mount *mp; /* mount table entry */ 3351541Srgrimes int docache; /* == 0 do not cache last component */ 3361541Srgrimes int wantparent; /* 1 => wantparent or lockparent flag */ 3371541Srgrimes int rdonly; /* lookup read-only flag bit */ 3389804Sbde int trailing_slash; 3391541Srgrimes int error = 0; 34065805Sbp int dpunlocked = 0; /* dp has already been unlocked */ 3411541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 34283366Sjulian struct thread *td = cnp->cn_thread; 343140714Sjeff int vfslocked; 344140714Sjeff int tvfslocked; 3451541Srgrimes 3461541Srgrimes /* 3471541Srgrimes * Setup: break out flag bits into variables. 3481541Srgrimes */ 349140714Sjeff vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; 350140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 3511541Srgrimes wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 3521541Srgrimes docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 3531541Srgrimes if (cnp->cn_nameiop == DELETE || 35422874Sbde (wantparent && cnp->cn_nameiop != CREATE && 35522874Sbde cnp->cn_nameiop != LOOKUP)) 3561541Srgrimes docache = 0; 3571541Srgrimes rdonly = cnp->cn_flags & RDONLY; 3581541Srgrimes ndp->ni_dvp = NULL; 3591541Srgrimes cnp->cn_flags &= ~ISSYMLINK; 3601541Srgrimes dp = ndp->ni_startdir; 3611541Srgrimes ndp->ni_startdir = NULLVP; 36283366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 3631541Srgrimes 3641541Srgrimesdirloop: 3651541Srgrimes /* 3661541Srgrimes * Search a new directory. 3671541Srgrimes * 3681541Srgrimes * The last component of the filename is left accessible via 3691541Srgrimes * cnp->cn_nameptr for callers that need the name. Callers needing 3701541Srgrimes * the name set the SAVENAME flag. When done, they assume 3711541Srgrimes * responsibility for freeing the pathname buffer. 3721541Srgrimes */ 3731541Srgrimes cnp->cn_consume = 0; 3741541Srgrimes for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 37551906Sphk continue; 3761541Srgrimes cnp->cn_namelen = cp - cnp->cn_nameptr; 3771541Srgrimes if (cnp->cn_namelen > NAME_MAX) { 3781541Srgrimes error = ENAMETOOLONG; 3791541Srgrimes goto bad; 3801541Srgrimes } 3811541Srgrimes#ifdef NAMEI_DIAGNOSTIC 3821541Srgrimes { char c = *cp; 3831541Srgrimes *cp = '\0'; 3841541Srgrimes printf("{%s}: ", cnp->cn_nameptr); 3851541Srgrimes *cp = c; } 3861541Srgrimes#endif 3871541Srgrimes ndp->ni_pathlen -= cnp->cn_namelen; 3881541Srgrimes ndp->ni_next = cp; 3899804Sbde 3909804Sbde /* 3919804Sbde * Replace multiple slashes by a single slash and trailing slashes 3929804Sbde * by a null. This must be done before VOP_LOOKUP() because some 3939804Sbde * fs's don't know about trailing slashes. Remember if there were 3949804Sbde * trailing slashes to handle symlinks, existing non-directories 3959804Sbde * and non-existing files that won't be directories specially later. 3969804Sbde */ 3979804Sbde trailing_slash = 0; 3989804Sbde while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { 3999804Sbde cp++; 4009804Sbde ndp->ni_pathlen--; 4019804Sbde if (*cp == '\0') { 4029804Sbde trailing_slash = 1; 4039804Sbde *ndp->ni_next = '\0'; /* XXX for direnter() ... */ 4049804Sbde } 4059804Sbde } 4069804Sbde ndp->ni_next = cp; 4079804Sbde 4081541Srgrimes cnp->cn_flags |= MAKEENTRY; 4091541Srgrimes if (*cp == '\0' && docache == 0) 4101541Srgrimes cnp->cn_flags &= ~MAKEENTRY; 4111541Srgrimes if (cnp->cn_namelen == 2 && 4121541Srgrimes cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 4131541Srgrimes cnp->cn_flags |= ISDOTDOT; 4141541Srgrimes else 4151541Srgrimes cnp->cn_flags &= ~ISDOTDOT; 4161541Srgrimes if (*ndp->ni_next == 0) 4171541Srgrimes cnp->cn_flags |= ISLASTCN; 4181541Srgrimes else 4191541Srgrimes cnp->cn_flags &= ~ISLASTCN; 4201541Srgrimes 4211541Srgrimes 4221541Srgrimes /* 4231541Srgrimes * Check for degenerate name (e.g. / or "") 4241541Srgrimes * which is a way of talking about a directory, 4251541Srgrimes * e.g. like "/." or ".". 4261541Srgrimes */ 4271541Srgrimes if (cnp->cn_nameptr[0] == '\0') { 42822521Sdyson if (dp->v_type != VDIR) { 42922521Sdyson error = ENOTDIR; 43022521Sdyson goto bad; 43122521Sdyson } 4321541Srgrimes if (cnp->cn_nameiop != LOOKUP) { 4331541Srgrimes error = EISDIR; 4341541Srgrimes goto bad; 4351541Srgrimes } 4361541Srgrimes if (wantparent) { 4371541Srgrimes ndp->ni_dvp = dp; 4381541Srgrimes VREF(dp); 4391541Srgrimes } 4401541Srgrimes ndp->ni_vp = dp; 4411541Srgrimes if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 44283366Sjulian VOP_UNLOCK(dp, 0, td); 44354655Seivind /* XXX This should probably move to the top of function. */ 4441541Srgrimes if (cnp->cn_flags & SAVESTART) 4451541Srgrimes panic("lookup: SAVESTART"); 446140714Sjeff goto success; 4471541Srgrimes } 4481541Srgrimes 4491541Srgrimes /* 4501541Srgrimes * Handle "..": two special cases. 4511541Srgrimes * 1. If at root directory (e.g. after chroot) 4521541Srgrimes * or at absolute root directory 4531541Srgrimes * then ignore it so can't get out. 4541541Srgrimes * 2. If this vnode is the root of a mounted 4551541Srgrimes * filesystem, then replace it with the 4561541Srgrimes * vnode which was mounted on so we take the 45796755Strhodes * .. in the other filesystem. 45851649Sphk * 3. If the vnode is the top directory of 45951649Sphk * the jail or chroot, don't let them out. 4601541Srgrimes */ 4611541Srgrimes if (cnp->cn_flags & ISDOTDOT) { 4621541Srgrimes for (;;) { 46351649Sphk if (dp == ndp->ni_rootdir || 46451649Sphk dp == ndp->ni_topdir || 46551649Sphk dp == rootvnode) { 4661541Srgrimes ndp->ni_dvp = dp; 4671541Srgrimes ndp->ni_vp = dp; 4681541Srgrimes VREF(dp); 4691541Srgrimes goto nextname; 4701541Srgrimes } 471101308Sjeff if ((dp->v_vflag & VV_ROOT) == 0 || 4721541Srgrimes (cnp->cn_flags & NOCROSSMOUNT)) 4731541Srgrimes break; 47469405Salfred if (dp->v_mount == NULL) { /* forced unmount */ 47569405Salfred error = EBADF; 47669405Salfred goto bad; 47769405Salfred } 4781541Srgrimes tdp = dp; 479140714Sjeff tvfslocked = vfslocked; 4801541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 4811541Srgrimes vput(tdp); 482140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 483140714Sjeff VFS_UNLOCK_GIANT(tvfslocked); 4841541Srgrimes VREF(dp); 48583366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 4861541Srgrimes } 4871541Srgrimes } 4881541Srgrimes 4891541Srgrimes /* 4901541Srgrimes * We now have a segment name to search for, and a directory to search. 4911541Srgrimes */ 4921541Srgrimesunionlookup: 493101127Srwatson#ifdef MAC 494105479Srwatson if ((cnp->cn_flags & NOMACCHECK) == 0) { 495105479Srwatson error = mac_check_vnode_lookup(td->td_ucred, dp, cnp); 496105479Srwatson if (error) 497105479Srwatson goto bad; 498105479Srwatson } 499101127Srwatson#endif 5001541Srgrimes ndp->ni_dvp = dp; 50122521Sdyson ndp->ni_vp = NULL; 50265973Sbp cnp->cn_flags &= ~PDIRUNLOCK; 50324624Sdfr ASSERT_VOP_LOCKED(dp, "lookup"); 504138345Sphk#ifdef NAMEI_DIAGNOSTIC 505138345Sphk vprint("lookup in", dp); 506138345Sphk#endif 50743301Sdillon if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { 50842408Seivind KASSERT(ndp->ni_vp == NULL, ("leaf should be empty")); 5091541Srgrimes#ifdef NAMEI_DIAGNOSTIC 5101541Srgrimes printf("not found\n"); 5111541Srgrimes#endif 5121541Srgrimes if ((error == ENOENT) && 513101308Sjeff (dp->v_vflag & VV_ROOT) && (dp->v_mount != NULL) && 5141541Srgrimes (dp->v_mount->mnt_flag & MNT_UNION)) { 5151541Srgrimes tdp = dp; 516140714Sjeff tvfslocked = vfslocked; 5171541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 51865973Sbp if (cnp->cn_flags & PDIRUNLOCK) 51965973Sbp vrele(tdp); 52065973Sbp else 52165973Sbp vput(tdp); 522140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 523140714Sjeff VFS_UNLOCK_GIANT(tvfslocked); 5241541Srgrimes VREF(dp); 52583366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 5261541Srgrimes goto unionlookup; 5271541Srgrimes } 5281541Srgrimes 5291541Srgrimes if (error != EJUSTRETURN) 5301541Srgrimes goto bad; 5311541Srgrimes /* 5321541Srgrimes * If creating and at end of pathname, then can consider 5331541Srgrimes * allowing file to be created. 5341541Srgrimes */ 53511644Sdg if (rdonly) { 5361541Srgrimes error = EROFS; 5371541Srgrimes goto bad; 5381541Srgrimes } 5399804Sbde if (*cp == '\0' && trailing_slash && 5409804Sbde !(cnp->cn_flags & WILLBEDIR)) { 5419804Sbde error = ENOENT; 5429804Sbde goto bad; 5439804Sbde } 5441541Srgrimes /* 5451541Srgrimes * We return with ni_vp NULL to indicate that the entry 5461541Srgrimes * doesn't currently exist, leaving a pointer to the 5471541Srgrimes * (possibly locked) directory inode in ndp->ni_dvp. 5481541Srgrimes */ 5491541Srgrimes if (cnp->cn_flags & SAVESTART) { 5501541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 5511541Srgrimes VREF(ndp->ni_startdir); 5521541Srgrimes } 553140714Sjeff goto success; 5541541Srgrimes } 5551541Srgrimes#ifdef NAMEI_DIAGNOSTIC 5561541Srgrimes printf("found\n"); 5571541Srgrimes#endif 5581541Srgrimes 55924624Sdfr ASSERT_VOP_LOCKED(ndp->ni_vp, "lookup"); 56024624Sdfr 5611541Srgrimes /* 5621541Srgrimes * Take into account any additional components consumed by 5631541Srgrimes * the underlying filesystem. 5641541Srgrimes */ 5651541Srgrimes if (cnp->cn_consume > 0) { 5661541Srgrimes cnp->cn_nameptr += cnp->cn_consume; 5671541Srgrimes ndp->ni_next += cnp->cn_consume; 5681541Srgrimes ndp->ni_pathlen -= cnp->cn_consume; 5691541Srgrimes cnp->cn_consume = 0; 5701541Srgrimes } 5711541Srgrimes 5721541Srgrimes dp = ndp->ni_vp; 5731541Srgrimes 5741541Srgrimes /* 5751541Srgrimes * Check to see if the vnode has been mounted on; 57696755Strhodes * if so find the root of the mounted filesystem. 5771541Srgrimes */ 5781541Srgrimes while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 5791541Srgrimes (cnp->cn_flags & NOCROSSMOUNT) == 0) { 58083366Sjulian if (vfs_busy(mp, 0, 0, td)) 5811541Srgrimes continue; 58283366Sjulian VOP_UNLOCK(dp, 0, td); 583140714Sjeff tvfslocked = VFS_LOCK_GIANT(mp); 584132023Salfred error = VFS_ROOT(mp, &tdp, td); 58583366Sjulian vfs_unbusy(mp, td); 58665805Sbp if (error) { 587140714Sjeff VFS_UNLOCK_GIANT(tvfslocked); 58865805Sbp dpunlocked = 1; 5891541Srgrimes goto bad2; 59065805Sbp } 59165805Sbp vrele(dp); 592140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 5931541Srgrimes ndp->ni_vp = dp = tdp; 594140714Sjeff vfslocked = tvfslocked; 5951541Srgrimes } 5961541Srgrimes 59710219Sdfr /* 59810219Sdfr * Check for symbolic link 59910219Sdfr */ 60010219Sdfr if ((dp->v_type == VLNK) && 60110219Sdfr ((cnp->cn_flags & FOLLOW) || trailing_slash || 60210219Sdfr *ndp->ni_next == '/')) { 60310219Sdfr cnp->cn_flags |= ISSYMLINK; 60469405Salfred if (dp->v_mount == NULL) { 60569405Salfred /* We can't know whether the directory was mounted with 60669405Salfred * NOSYMFOLLOW, so we can't follow safely. */ 60769405Salfred error = EBADF; 60869405Salfred goto bad2; 60969405Salfred } 61035105Swosch if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) { 61135105Swosch error = EACCES; 61235105Swosch goto bad2; 61335105Swosch } 614140714Sjeff goto success; 61510219Sdfr } 61610219Sdfr 61710219Sdfr /* 61810219Sdfr * Check for bogus trailing slashes. 61910219Sdfr */ 62010219Sdfr if (trailing_slash && dp->v_type != VDIR) { 62110219Sdfr error = ENOTDIR; 62210219Sdfr goto bad2; 62310219Sdfr } 62410219Sdfr 6251541Srgrimesnextname: 6261541Srgrimes /* 6271541Srgrimes * Not a symbolic link. If more pathname, 6281541Srgrimes * continue at next component, else return. 6291541Srgrimes */ 6301541Srgrimes if (*ndp->ni_next == '/') { 6311541Srgrimes cnp->cn_nameptr = ndp->ni_next; 6321541Srgrimes while (*cnp->cn_nameptr == '/') { 6331541Srgrimes cnp->cn_nameptr++; 6341541Srgrimes ndp->ni_pathlen--; 6351541Srgrimes } 63654655Seivind if (ndp->ni_dvp != ndp->ni_vp) 63754655Seivind ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup"); 6381541Srgrimes vrele(ndp->ni_dvp); 6391541Srgrimes goto dirloop; 6401541Srgrimes } 6411541Srgrimes /* 64296755Strhodes * Disallow directory write attempts on read-only filesystems. 6431541Srgrimes */ 64411644Sdg if (rdonly && 64511644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 64611644Sdg error = EROFS; 64711644Sdg goto bad2; 6481541Srgrimes } 6491541Srgrimes if (cnp->cn_flags & SAVESTART) { 6501541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 6511541Srgrimes VREF(ndp->ni_startdir); 6521541Srgrimes } 6531541Srgrimes if (!wantparent) 6541541Srgrimes vrele(ndp->ni_dvp); 65532071Sdyson 6561541Srgrimes if ((cnp->cn_flags & LOCKLEAF) == 0) 65783366Sjulian VOP_UNLOCK(dp, 0, td); 658140714Sjeffsuccess: 659140714Sjeff if (vfslocked) 660140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 6611541Srgrimes return (0); 6621541Srgrimes 6631541Srgrimesbad2: 66465973Sbp if ((cnp->cn_flags & (LOCKPARENT | PDIRUNLOCK)) == LOCKPARENT && 66565973Sbp *ndp->ni_next == '\0') 66683366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 6671541Srgrimes vrele(ndp->ni_dvp); 6681541Srgrimesbad: 66965805Sbp if (dpunlocked) 67065805Sbp vrele(dp); 67165805Sbp else 67265805Sbp vput(dp); 673140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 674140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 6751541Srgrimes ndp->ni_vp = NULL; 6761541Srgrimes return (error); 6771541Srgrimes} 6781541Srgrimes 6793148Sphk/* 6803148Sphk * relookup - lookup a path name component 6813148Sphk * Used by lookup to re-aquire things. 6823148Sphk */ 6833148Sphkint 6843148Sphkrelookup(dvp, vpp, cnp) 6853148Sphk struct vnode *dvp, **vpp; 6863148Sphk struct componentname *cnp; 6873148Sphk{ 68883366Sjulian struct thread *td = cnp->cn_thread; 68922521Sdyson struct vnode *dp = 0; /* the directory we are searching */ 6903148Sphk int docache; /* == 0 do not cache last component */ 6913148Sphk int wantparent; /* 1 => wantparent or lockparent flag */ 6923148Sphk int rdonly; /* lookup read-only flag bit */ 6933148Sphk int error = 0; 6941541Srgrimes 6953148Sphk /* 6963148Sphk * Setup: break out flag bits into variables. 6973148Sphk */ 6983148Sphk wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 6993148Sphk docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 7003148Sphk if (cnp->cn_nameiop == DELETE || 7013148Sphk (wantparent && cnp->cn_nameiop != CREATE)) 7023148Sphk docache = 0; 7033148Sphk rdonly = cnp->cn_flags & RDONLY; 7043148Sphk cnp->cn_flags &= ~ISSYMLINK; 7053148Sphk dp = dvp; 70683366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 7073148Sphk 7083148Sphk/* dirloop: */ 7093148Sphk /* 7103148Sphk * Search a new directory. 7113148Sphk * 7123148Sphk * The last component of the filename is left accessible via 7133148Sphk * cnp->cn_nameptr for callers that need the name. Callers needing 7143148Sphk * the name set the SAVENAME flag. When done, they assume 7153148Sphk * responsibility for freeing the pathname buffer. 7163148Sphk */ 7173148Sphk#ifdef NAMEI_DIAGNOSTIC 7183148Sphk printf("{%s}: ", cnp->cn_nameptr); 7193148Sphk#endif 7203148Sphk 7213148Sphk /* 7223148Sphk * Check for degenerate name (e.g. / or "") 7233148Sphk * which is a way of talking about a directory, 7243148Sphk * e.g. like "/." or ".". 7253148Sphk */ 7263148Sphk if (cnp->cn_nameptr[0] == '\0') { 7273148Sphk if (cnp->cn_nameiop != LOOKUP || wantparent) { 7283148Sphk error = EISDIR; 7293148Sphk goto bad; 7303148Sphk } 7313148Sphk if (dp->v_type != VDIR) { 7323148Sphk error = ENOTDIR; 7333148Sphk goto bad; 7343148Sphk } 7353148Sphk if (!(cnp->cn_flags & LOCKLEAF)) 73683366Sjulian VOP_UNLOCK(dp, 0, td); 7373148Sphk *vpp = dp; 73854655Seivind /* XXX This should probably move to the top of function. */ 7393148Sphk if (cnp->cn_flags & SAVESTART) 7403148Sphk panic("lookup: SAVESTART"); 7413148Sphk return (0); 7423148Sphk } 7433148Sphk 7443148Sphk if (cnp->cn_flags & ISDOTDOT) 7453148Sphk panic ("relookup: lookup on dot-dot"); 7463148Sphk 7473148Sphk /* 7483148Sphk * We now have a segment name to search for, and a directory to search. 7493148Sphk */ 750138345Sphk#ifdef NAMEI_DIAGNOSTIC 751138345Sphk vprint("search in:", dp); 752138345Sphk#endif 75343311Sdillon if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { 75442408Seivind KASSERT(*vpp == NULL, ("leaf should be empty")); 7553148Sphk if (error != EJUSTRETURN) 7563148Sphk goto bad; 7573148Sphk /* 7583148Sphk * If creating and at end of pathname, then can consider 7593148Sphk * allowing file to be created. 7603148Sphk */ 76111644Sdg if (rdonly) { 7623148Sphk error = EROFS; 7633148Sphk goto bad; 7643148Sphk } 7653148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 7663148Sphk if (cnp->cn_flags & SAVESTART) 7673148Sphk VREF(dvp); 7683148Sphk /* 7693148Sphk * We return with ni_vp NULL to indicate that the entry 7703148Sphk * doesn't currently exist, leaving a pointer to the 7713148Sphk * (possibly locked) directory inode in ndp->ni_dvp. 7723148Sphk */ 7733148Sphk return (0); 7743148Sphk } 7753148Sphk dp = *vpp; 7763148Sphk 7773148Sphk /* 7783148Sphk * Check for symbolic link 7793148Sphk */ 78042408Seivind KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW), 78142453Seivind ("relookup: symlink found.\n")); 7823148Sphk 7833148Sphk /* 78496755Strhodes * Disallow directory write attempts on read-only filesystems. 7853148Sphk */ 78611644Sdg if (rdonly && 78711644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 78811644Sdg error = EROFS; 78911644Sdg goto bad2; 7903148Sphk } 7913148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 7923148Sphk if (cnp->cn_flags & SAVESTART) 7933148Sphk VREF(dvp); 79422521Sdyson 7953148Sphk if (!wantparent) 7963148Sphk vrele(dvp); 79732071Sdyson 7983148Sphk if ((cnp->cn_flags & LOCKLEAF) == 0) 79983366Sjulian VOP_UNLOCK(dp, 0, td); 8003148Sphk return (0); 8013148Sphk 8023148Sphkbad2: 8033148Sphk if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 80483366Sjulian VOP_UNLOCK(dvp, 0, td); 8053148Sphk vrele(dvp); 8063148Sphkbad: 8073148Sphk vput(dp); 8083148Sphk *vpp = NULL; 8093148Sphk return (error); 8103148Sphk} 811141471Sjhb 812141471Sjhb/* 813141471Sjhb * Determine if there is a suitable alternate filename under the specified 814141471Sjhb * prefix for the specified path. If the create flag is set, then the 815141471Sjhb * alternate prefix will be used so long as the parent directory exists. 816141471Sjhb * This is used by the various compatiblity ABIs so that Linux binaries prefer 817141471Sjhb * files under /compat/linux for example. The chosen path (whether under 818141471Sjhb * the prefix or under /) is returned in a kernel malloc'd buffer pointed 819141471Sjhb * to by pathbuf. The caller is responsible for free'ing the buffer from 820141471Sjhb * the M_TEMP bucket if one is returned. 821141471Sjhb */ 822141471Sjhbint 823141471Sjhbkern_alternate_path(struct thread *td, const char *prefix, char *path, 824141471Sjhb enum uio_seg pathseg, char **pathbuf, int create) 825141471Sjhb{ 826141471Sjhb struct nameidata nd, ndroot; 827141471Sjhb char *ptr, *buf, *cp; 828141471Sjhb size_t len, sz; 829141471Sjhb int error; 830141471Sjhb 831141471Sjhb buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 832141471Sjhb *pathbuf = buf; 833141471Sjhb 834141471Sjhb /* Copy the prefix into the new pathname as a starting point. */ 835141471Sjhb len = strlcpy(buf, prefix, MAXPATHLEN); 836141471Sjhb if (len >= MAXPATHLEN) { 837141471Sjhb *pathbuf = NULL; 838141471Sjhb free(buf, M_TEMP); 839141471Sjhb return (EINVAL); 840141471Sjhb } 841141471Sjhb sz = MAXPATHLEN - len; 842141471Sjhb ptr = buf + len; 843141471Sjhb 844141471Sjhb /* Append the filename to the prefix. */ 845141471Sjhb if (pathseg == UIO_SYSSPACE) 846141471Sjhb error = copystr(path, ptr, sz, &len); 847141471Sjhb else 848141471Sjhb error = copyinstr(path, ptr, sz, &len); 849141471Sjhb 850141471Sjhb if (error) { 851141471Sjhb *pathbuf = NULL; 852141471Sjhb free(buf, M_TEMP); 853141471Sjhb return (error); 854141471Sjhb } 855141471Sjhb 856141471Sjhb /* Only use a prefix with absolute pathnames. */ 857141471Sjhb if (*ptr != '/') { 858141471Sjhb error = EINVAL; 859141471Sjhb goto keeporig; 860141471Sjhb } 861141471Sjhb 862141471Sjhb /* XXX: VFS_LOCK_GIANT? */ 863141471Sjhb mtx_lock(&Giant); 864141471Sjhb 865141471Sjhb /* 866141471Sjhb * We know that there is a / somewhere in this pathname. 867141471Sjhb * Search backwards for it, to find the file's parent dir 868141471Sjhb * to see if it exists in the alternate tree. If it does, 869141471Sjhb * and we want to create a file (cflag is set). We don't 870141471Sjhb * need to worry about the root comparison in this case. 871141471Sjhb */ 872141471Sjhb 873141471Sjhb if (create) { 874141471Sjhb for (cp = &ptr[len] - 1; *cp != '/'; cp--); 875141471Sjhb *cp = '\0'; 876141471Sjhb 877141471Sjhb NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td); 878141471Sjhb error = namei(&nd); 879141471Sjhb *cp = '/'; 880141471Sjhb if (error != 0) 881141471Sjhb goto nd_failed; 882141471Sjhb } else { 883141471Sjhb NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td); 884141471Sjhb 885141471Sjhb error = namei(&nd); 886141471Sjhb if (error != 0) 887141471Sjhb goto nd_failed; 888141471Sjhb 889141471Sjhb /* 890141471Sjhb * We now compare the vnode of the prefix to the one 891141471Sjhb * vnode asked. If they resolve to be the same, then we 892141471Sjhb * ignore the match so that the real root gets used. 893141471Sjhb * This avoids the problem of traversing "../.." to find the 894141471Sjhb * root directory and never finding it, because "/" resolves 895141471Sjhb * to the emulation root directory. This is expensive :-( 896141471Sjhb */ 897141471Sjhb NDINIT(&ndroot, LOOKUP, FOLLOW, UIO_SYSSPACE, prefix, td); 898141471Sjhb 899141471Sjhb /* We shouldn't ever get an error from this namei(). */ 900141471Sjhb error = namei(&ndroot); 901141471Sjhb if (error == 0) { 902141471Sjhb if (nd.ni_vp == ndroot.ni_vp) 903141471Sjhb error = ENOENT; 904141471Sjhb 905141471Sjhb NDFREE(&ndroot, NDF_ONLY_PNBUF); 906141471Sjhb vrele(ndroot.ni_vp); 907141471Sjhb } 908141471Sjhb } 909141471Sjhb 910141471Sjhb NDFREE(&nd, NDF_ONLY_PNBUF); 911141471Sjhb vrele(nd.ni_vp); 912141471Sjhb 913141471Sjhbnd_failed: 914141471Sjhb /* XXX: VFS_UNLOCK_GIANT? */ 915141471Sjhb mtx_unlock(&Giant); 916141471Sjhb 917141471Sjhbkeeporig: 918141471Sjhb /* If there was an error, use the original path name. */ 919141471Sjhb if (error) 920141471Sjhb bcopy(ptr, buf, len); 921141471Sjhb return (error); 922141471Sjhb} 923