Home | History | Annotate | Line # | Download | only in kern
vfs_lookup.c revision 1.121.2.1
      1  1.121.2.1  uebayasi /*	$NetBSD: vfs_lookup.c,v 1.121.2.1 2010/08/17 06:47:33 uebayasi Exp $	*/
      2       1.13       cgd 
      3       1.10       cgd /*
      4       1.12   mycroft  * Copyright (c) 1982, 1986, 1989, 1993
      5       1.12   mycroft  *	The Regents of the University of California.  All rights reserved.
      6       1.10       cgd  * (c) UNIX System Laboratories, Inc.
      7       1.10       cgd  * All or some portions of this file are derived from material licensed
      8       1.10       cgd  * to the University of California by American Telephone and Telegraph
      9       1.10       cgd  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     10       1.10       cgd  * the permission of UNIX System Laboratories, Inc.
     11       1.10       cgd  *
     12       1.10       cgd  * Redistribution and use in source and binary forms, with or without
     13       1.10       cgd  * modification, are permitted provided that the following conditions
     14       1.10       cgd  * are met:
     15       1.10       cgd  * 1. Redistributions of source code must retain the above copyright
     16       1.10       cgd  *    notice, this list of conditions and the following disclaimer.
     17       1.10       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     18       1.10       cgd  *    notice, this list of conditions and the following disclaimer in the
     19       1.10       cgd  *    documentation and/or other materials provided with the distribution.
     20       1.49       agc  * 3. Neither the name of the University nor the names of its contributors
     21       1.10       cgd  *    may be used to endorse or promote products derived from this software
     22       1.10       cgd  *    without specific prior written permission.
     23       1.10       cgd  *
     24       1.10       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25       1.10       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26       1.10       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27       1.10       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28       1.10       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29       1.10       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30       1.10       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31       1.10       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32       1.10       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33       1.10       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34       1.10       cgd  * SUCH DAMAGE.
     35       1.10       cgd  *
     36       1.26      fvdl  *	@(#)vfs_lookup.c	8.10 (Berkeley) 5/27/95
     37       1.10       cgd  */
     38       1.38     lukem 
     39       1.38     lukem #include <sys/cdefs.h>
     40  1.121.2.1  uebayasi __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.121.2.1 2010/08/17 06:47:33 uebayasi Exp $");
     41       1.27   thorpej 
     42       1.67       chs #include "opt_magiclinks.h"
     43       1.10       cgd 
     44       1.10       cgd #include <sys/param.h>
     45       1.15       cgd #include <sys/systm.h>
     46       1.61   thorpej #include <sys/kernel.h>
     47       1.10       cgd #include <sys/syslimits.h>
     48       1.10       cgd #include <sys/time.h>
     49       1.10       cgd #include <sys/namei.h>
     50       1.10       cgd #include <sys/vnode.h>
     51       1.10       cgd #include <sys/mount.h>
     52       1.10       cgd #include <sys/errno.h>
     53       1.39     lukem #include <sys/filedesc.h>
     54       1.39     lukem #include <sys/hash.h>
     55       1.10       cgd #include <sys/proc.h>
     56       1.40  wrstuden #include <sys/syslog.h>
     57       1.70      elad #include <sys/kauth.h>
     58       1.97        ad #include <sys/ktrace.h>
     59       1.12   mycroft 
     60       1.67       chs #ifndef MAGICLINKS
     61       1.67       chs #define MAGICLINKS 0
     62       1.67       chs #endif
     63       1.67       chs 
     64       1.76      elad struct pathname_internal {
     65       1.76      elad 	char *pathbuf;
     66       1.83   thorpej 	bool needfree;
     67       1.76      elad };
     68       1.76      elad 
     69       1.67       chs int vfs_magiclinks = MAGICLINKS;
     70       1.67       chs 
     71       1.99        ad pool_cache_t pnbuf_cache;	/* pathname buffer cache */
     72       1.44   thorpej 
     73       1.10       cgd /*
     74       1.61   thorpej  * Substitute replacement text for 'magic' strings in symlinks.
     75       1.61   thorpej  * Returns 0 if successful, and returns non-zero if an error
     76       1.61   thorpej  * occurs.  (Currently, the only possible error is running out
     77       1.61   thorpej  * of temporary pathname space.)
     78       1.61   thorpej  *
     79       1.61   thorpej  * Looks for "@<string>" and "@<string>/", where <string> is a
     80       1.61   thorpej  * recognized 'magic' string.  Replaces the "@<string>" with the
     81       1.61   thorpej  * appropriate replacement text.  (Note that in some cases the
     82       1.61   thorpej  * replacement text may have zero length.)
     83       1.61   thorpej  *
     84       1.61   thorpej  * This would have been table driven, but the variance in
     85       1.61   thorpej  * replacement strings (and replacement string lengths) made
     86       1.61   thorpej  * that impractical.
     87       1.61   thorpej  */
     88       1.63   thorpej #define	VNL(x)							\
     89       1.63   thorpej 	(sizeof(x) - 1)
     90       1.63   thorpej 
     91       1.63   thorpej #define	VO	'{'
     92       1.63   thorpej #define	VC	'}'
     93       1.63   thorpej 
     94       1.61   thorpej #define	MATCH(str)						\
     95       1.63   thorpej 	((termchar == '/' && i + VNL(str) == *len) ||		\
     96       1.63   thorpej 	 (i + VNL(str) < *len &&				\
     97       1.63   thorpej 	  cp[i + VNL(str)] == termchar)) &&			\
     98       1.63   thorpej 	!strncmp((str), &cp[i], VNL(str))
     99       1.61   thorpej 
    100       1.61   thorpej #define	SUBSTITUTE(m, s, sl)					\
    101      1.115  christos 	if ((newlen + (sl)) >= MAXPATHLEN)			\
    102      1.115  christos 		return 1;					\
    103       1.63   thorpej 	i += VNL(m);						\
    104       1.63   thorpej 	if (termchar != '/')					\
    105       1.63   thorpej 		i++;						\
    106      1.115  christos 	(void)memcpy(&tmp[newlen], (s), (sl));			\
    107       1.63   thorpej 	newlen += (sl);						\
    108       1.63   thorpej 	change = 1;						\
    109       1.63   thorpej 	termchar = '/';
    110       1.61   thorpej 
    111       1.61   thorpej static int
    112      1.115  christos symlink_magic(struct proc *p, char *cp, size_t *len)
    113       1.61   thorpej {
    114       1.66      yamt 	char *tmp;
    115      1.115  christos 	size_t change, i, newlen, slen;
    116      1.115  christos 	char termchar = '/';
    117      1.115  christos 	char idtmp[11]; /* enough for 32 bit *unsigned* integer */
    118      1.101       mjf 
    119       1.61   thorpej 
    120       1.66      yamt 	tmp = PNBUF_GET();
    121       1.61   thorpej 	for (change = i = newlen = 0; i < *len; ) {
    122       1.63   thorpej 		if (cp[i] != '@') {
    123       1.61   thorpej 			tmp[newlen++] = cp[i++];
    124       1.63   thorpej 			continue;
    125       1.63   thorpej 		}
    126       1.63   thorpej 
    127       1.63   thorpej 		i++;
    128       1.63   thorpej 
    129       1.63   thorpej 		/* Check for @{var} syntax. */
    130       1.63   thorpej 		if (cp[i] == VO) {
    131       1.63   thorpej 			termchar = VC;
    132       1.61   thorpej 			i++;
    133       1.63   thorpej 		}
    134       1.63   thorpej 
    135       1.63   thorpej 		/*
    136       1.63   thorpej 		 * The following checks should be ordered according
    137       1.63   thorpej 		 * to frequency of use.
    138       1.63   thorpej 		 */
    139       1.63   thorpej 		if (MATCH("machine_arch")) {
    140      1.115  christos 			slen = VNL(MACHINE_ARCH);
    141      1.115  christos 			SUBSTITUTE("machine_arch", MACHINE_ARCH, slen);
    142       1.63   thorpej 		} else if (MATCH("machine")) {
    143      1.115  christos 			slen = VNL(MACHINE);
    144      1.115  christos 			SUBSTITUTE("machine", MACHINE, slen);
    145       1.63   thorpej 		} else if (MATCH("hostname")) {
    146      1.115  christos 			SUBSTITUTE("hostname", hostname, hostnamelen);
    147       1.63   thorpej 		} else if (MATCH("osrelease")) {
    148      1.115  christos 			slen = strlen(osrelease);
    149      1.115  christos 			SUBSTITUTE("osrelease", osrelease, slen);
    150       1.63   thorpej 		} else if (MATCH("emul")) {
    151      1.115  christos 			slen = strlen(p->p_emul->e_name);
    152      1.115  christos 			SUBSTITUTE("emul", p->p_emul->e_name, slen);
    153       1.63   thorpej 		} else if (MATCH("kernel_ident")) {
    154      1.115  christos 			slen = strlen(kernel_ident);
    155      1.115  christos 			SUBSTITUTE("kernel_ident", kernel_ident, slen);
    156       1.63   thorpej 		} else if (MATCH("domainname")) {
    157      1.115  christos 			SUBSTITUTE("domainname", domainname, domainnamelen);
    158       1.63   thorpej 		} else if (MATCH("ostype")) {
    159      1.115  christos 			slen = strlen(ostype);
    160      1.115  christos 			SUBSTITUTE("ostype", ostype, slen);
    161       1.72      elad 		} else if (MATCH("uid")) {
    162      1.115  christos 			slen = snprintf(idtmp, sizeof(idtmp), "%u",
    163       1.72      elad 			    kauth_cred_geteuid(kauth_cred_get()));
    164      1.115  christos 			SUBSTITUTE("uid", idtmp, slen);
    165      1.101       mjf 		} else if (MATCH("ruid")) {
    166      1.115  christos 			slen = snprintf(idtmp, sizeof(idtmp), "%u",
    167      1.101       mjf 			    kauth_cred_getuid(kauth_cred_get()));
    168      1.115  christos 			SUBSTITUTE("ruid", idtmp, slen);
    169      1.115  christos 		} else if (MATCH("gid")) {
    170      1.115  christos 			slen = snprintf(idtmp, sizeof(idtmp), "%u",
    171      1.115  christos 			    kauth_cred_getegid(kauth_cred_get()));
    172      1.115  christos 			SUBSTITUTE("gid", idtmp, slen);
    173      1.115  christos 		} else if (MATCH("rgid")) {
    174      1.115  christos 			slen = snprintf(idtmp, sizeof(idtmp), "%u",
    175      1.115  christos 			    kauth_cred_getgid(kauth_cred_get()));
    176      1.115  christos 			SUBSTITUTE("rgid", idtmp, slen);
    177       1.63   thorpej 		} else {
    178       1.63   thorpej 			tmp[newlen++] = '@';
    179       1.63   thorpej 			if (termchar == VC)
    180       1.63   thorpej 				tmp[newlen++] = VO;
    181       1.61   thorpej 		}
    182       1.61   thorpej 	}
    183       1.61   thorpej 
    184       1.66      yamt 	if (change) {
    185      1.115  christos 		(void)memcpy(cp, tmp, newlen);
    186       1.66      yamt 		*len = newlen;
    187       1.66      yamt 	}
    188       1.66      yamt 	PNBUF_PUT(tmp);
    189       1.61   thorpej 
    190      1.115  christos 	return 0;
    191       1.61   thorpej }
    192       1.61   thorpej 
    193       1.63   thorpej #undef VNL
    194       1.63   thorpej #undef VO
    195       1.63   thorpej #undef VC
    196       1.63   thorpej #undef MATCH
    197       1.63   thorpej #undef SUBSTITUTE
    198       1.63   thorpej 
    199       1.61   thorpej /*
    200       1.69    rumble  * Convert a pathname into a pointer to a locked vnode.
    201       1.10       cgd  *
    202       1.10       cgd  * The FOLLOW flag is set when symbolic links are to be followed
    203       1.10       cgd  * when they occur at the end of the name translation process.
    204       1.10       cgd  * Symbolic links are always followed for all other pathname
    205       1.10       cgd  * components other than the last.
    206       1.10       cgd  *
    207       1.10       cgd  * The segflg defines whether the name is to be copied from user
    208       1.10       cgd  * space or kernel space.
    209       1.10       cgd  *
    210       1.10       cgd  * Overall outline of namei:
    211       1.10       cgd  *
    212       1.10       cgd  *	copy in name
    213       1.10       cgd  *	get starting directory
    214       1.10       cgd  *	while (!done && !error) {
    215       1.10       cgd  *		call lookup to search path.
    216       1.10       cgd  *		if symbolic link, massage name in buffer and continue
    217       1.10       cgd  *	}
    218       1.10       cgd  */
    219      1.117  dholland 
    220      1.117  dholland /*
    221      1.117  dholland  * Internal state for a namei operation.
    222      1.117  dholland  */
    223      1.117  dholland struct namei_state {
    224      1.117  dholland 	struct nameidata *ndp;
    225      1.117  dholland 	struct componentname *cnp;
    226      1.117  dholland 
    227      1.118  dholland 	/* used by the pieces of namei */
    228      1.118  dholland 	struct vnode *namei_startdir; /* The directory namei() starts from. */
    229      1.118  dholland 
    230      1.118  dholland 	/* used by the pieces of lookup */
    231      1.118  dholland 	int lookup_alldone;
    232      1.118  dholland 
    233      1.118  dholland 	int docache;			/* == 0 do not cache last component */
    234      1.118  dholland 	int rdonly;			/* lookup read-only flag bit */
    235      1.117  dholland 	struct vnode *dp;		/* the directory we are searching */
    236      1.118  dholland 	int slashes;
    237      1.117  dholland };
    238      1.117  dholland 
    239      1.118  dholland /* XXX reorder things to make this decl unnecessary */
    240      1.118  dholland static int do_lookup(struct namei_state *state);
    241      1.118  dholland 
    242      1.118  dholland 
    243      1.117  dholland /*
    244      1.117  dholland  * Initialize the namei working state.
    245      1.117  dholland  */
    246      1.117  dholland static void
    247      1.117  dholland namei_init(struct namei_state *state, struct nameidata *ndp)
    248      1.117  dholland {
    249      1.117  dholland 	state->ndp = ndp;
    250      1.117  dholland 	state->cnp = &ndp->ni_cnd;
    251      1.117  dholland 
    252      1.118  dholland 	state->namei_startdir = NULL;
    253      1.118  dholland 
    254      1.118  dholland 	state->lookup_alldone = 0;
    255      1.118  dholland 
    256      1.118  dholland 	state->docache = 0;
    257      1.118  dholland 	state->rdonly = 0;
    258      1.117  dholland 	state->dp = NULL;
    259      1.118  dholland 	state->slashes = 0;
    260      1.117  dholland }
    261      1.117  dholland 
    262      1.117  dholland /*
    263      1.117  dholland  * Clean up the working namei state, leaving things ready for return
    264      1.117  dholland  * from namei.
    265      1.117  dholland  */
    266      1.117  dholland static void
    267      1.117  dholland namei_cleanup(struct namei_state *state)
    268      1.117  dholland {
    269      1.117  dholland 	KASSERT(state->cnp == &state->ndp->ni_cnd);
    270      1.117  dholland 
    271      1.118  dholland 	//KASSERT(state->namei_startdir == NULL); 	// not yet
    272      1.117  dholland 
    273      1.117  dholland 	/* nothing for now */
    274      1.117  dholland 	(void)state;
    275      1.117  dholland }
    276      1.117  dholland 
    277      1.117  dholland //////////////////////////////
    278      1.117  dholland 
    279      1.117  dholland /*
    280      1.117  dholland  * Start up namei. Early portion.
    281      1.117  dholland  *
    282      1.117  dholland  * This is divided from namei_start2 by the emul_retry: point.
    283      1.117  dholland  */
    284      1.117  dholland static void
    285      1.117  dholland namei_start1(struct namei_state *state)
    286       1.10       cgd {
    287       1.10       cgd 
    288       1.12   mycroft #ifdef DIAGNOSTIC
    289      1.117  dholland 	if (!state->cnp->cn_cred)
    290       1.58  christos 		panic("namei: bad cred/proc");
    291      1.117  dholland 	if (state->cnp->cn_nameiop & (~OPMASK))
    292       1.58  christos 		panic("namei: nameiop contaminated with flags");
    293      1.117  dholland 	if (state->cnp->cn_flags & OPMASK)
    294       1.58  christos 		panic("namei: flags contaminated with nameiops");
    295       1.12   mycroft #endif
    296       1.10       cgd 
    297       1.10       cgd 	/*
    298       1.10       cgd 	 * Get a buffer for the name to be translated, and copy the
    299       1.10       cgd 	 * name into the buffer.
    300       1.10       cgd 	 */
    301      1.117  dholland 	if ((state->cnp->cn_flags & HASBUF) == 0)
    302      1.117  dholland 		state->cnp->cn_pnbuf = PNBUF_GET();
    303      1.117  dholland }
    304      1.117  dholland 
    305      1.117  dholland /*
    306      1.117  dholland  * Start up namei. Copy the path, find the root dir and cwd, establish
    307      1.117  dholland  * the starting directory for lookup, and lock it.
    308      1.117  dholland  */
    309      1.117  dholland static int
    310      1.117  dholland namei_start2(struct namei_state *state)
    311      1.117  dholland {
    312      1.117  dholland 	struct nameidata *ndp = state->ndp;
    313      1.117  dholland 	struct componentname *cnp = state->cnp;
    314      1.117  dholland 
    315      1.117  dholland 	struct cwdinfo *cwdi;		/* pointer to cwd state */
    316      1.117  dholland 	struct lwp *self = curlwp;	/* thread doing namei() */
    317      1.117  dholland 	int error;
    318      1.117  dholland 
    319       1.10       cgd 	if (ndp->ni_segflg == UIO_SYSSPACE)
    320       1.12   mycroft 		error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
    321       1.10       cgd 			    MAXPATHLEN, &ndp->ni_pathlen);
    322       1.10       cgd 	else
    323       1.12   mycroft 		error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
    324       1.10       cgd 			    MAXPATHLEN, &ndp->ni_pathlen);
    325       1.21    kleink 
    326       1.21    kleink 	/*
    327       1.21    kleink 	 * POSIX.1 requirement: "" is not a valid file name.
    328       1.56     perry 	 */
    329       1.21    kleink 	if (!error && ndp->ni_pathlen == 1)
    330       1.21    kleink 		error = ENOENT;
    331       1.21    kleink 
    332       1.10       cgd 	if (error) {
    333       1.35   thorpej 		PNBUF_PUT(cnp->cn_pnbuf);
    334       1.10       cgd 		ndp->ni_vp = NULL;
    335       1.10       cgd 		return (error);
    336       1.10       cgd 	}
    337       1.10       cgd 	ndp->ni_loopcnt = 0;
    338       1.21    kleink 
    339       1.10       cgd 	/*
    340       1.85       dsl 	 * Get root directory for the translation.
    341       1.10       cgd 	 */
    342      1.117  dholland 	cwdi = self->l_proc->p_cwdi;
    343       1.93        ad 	rw_enter(&cwdi->cwdi_lock, RW_READER);
    344      1.118  dholland 	state->namei_startdir = cwdi->cwdi_rdir;
    345      1.118  dholland 	if (state->namei_startdir == NULL)
    346      1.118  dholland 		state->namei_startdir = rootvnode;
    347      1.118  dholland 	ndp->ni_rootdir = state->namei_startdir;
    348       1.85       dsl 
    349       1.23   mycroft 	/*
    350       1.23   mycroft 	 * Check if starting from root directory or current directory.
    351       1.23   mycroft 	 */
    352       1.23   mycroft 	if (cnp->cn_pnbuf[0] == '/') {
    353       1.85       dsl 		if (cnp->cn_flags & TRYEMULROOT) {
    354       1.85       dsl 			if (cnp->cn_flags & EMULROOTSET) {
    355       1.89       dsl 				/* Called from (eg) emul_find_interp() */
    356      1.118  dholland 				state->namei_startdir = ndp->ni_erootdir;
    357       1.85       dsl 			} else {
    358       1.90       dsl 				if (cwdi->cwdi_edir == NULL
    359       1.90       dsl 				    || (cnp->cn_pnbuf[1] == '.'
    360       1.90       dsl 					   && cnp->cn_pnbuf[2] == '.'
    361       1.90       dsl 					   && cnp->cn_pnbuf[3] == '/')) {
    362       1.90       dsl 					ndp->ni_erootdir = NULL;
    363       1.90       dsl 				} else {
    364      1.118  dholland 					state->namei_startdir = cwdi->cwdi_edir;
    365      1.118  dholland 					ndp->ni_erootdir = state->namei_startdir;
    366       1.85       dsl 				}
    367       1.85       dsl 			}
    368      1.111        ad 		} else {
    369       1.85       dsl 			ndp->ni_erootdir = NULL;
    370      1.113     enami 			if (cnp->cn_flags & NOCHROOT)
    371      1.118  dholland 				state->namei_startdir = ndp->ni_rootdir = rootvnode;
    372      1.111        ad 		}
    373       1.23   mycroft 	} else {
    374      1.118  dholland 		state->namei_startdir = cwdi->cwdi_cdir;
    375       1.85       dsl 		ndp->ni_erootdir = NULL;
    376       1.23   mycroft 	}
    377      1.121     pooka 	vref(state->namei_startdir);
    378       1.93        ad 	rw_exit(&cwdi->cwdi_lock);
    379      1.117  dholland 
    380      1.117  dholland 	/*
    381      1.117  dholland 	 * Ktrace it.
    382      1.117  dholland 	 */
    383       1.97        ad 	if (ktrpoint(KTR_NAMEI)) {
    384       1.90       dsl 		if (ndp->ni_erootdir != NULL) {
    385       1.89       dsl 			/*
    386       1.89       dsl 			 * To make any sense, the trace entry need to have the
    387       1.89       dsl 			 * text of the emulation path prepended.
    388       1.89       dsl 			 * Usually we can get this from the current process,
    389       1.89       dsl 			 * but when called from emul_find_interp() it is only
    390       1.89       dsl 			 * in the exec_package - so we get it passed in ni_next
    391       1.89       dsl 			 * (this is a hack).
    392       1.89       dsl 			 */
    393       1.89       dsl 			const char *emul_path;
    394       1.88       dsl 			if (cnp->cn_flags & EMULROOTSET)
    395       1.89       dsl 				emul_path = ndp->ni_next;
    396       1.88       dsl 			else
    397      1.117  dholland 				emul_path = self->l_proc->p_emul->e_path;
    398       1.97        ad 			ktrnamei2(emul_path, strlen(emul_path),
    399       1.89       dsl 			    cnp->cn_pnbuf, ndp->ni_pathlen);
    400       1.88       dsl 		} else
    401       1.97        ad 			ktrnamei(cnp->cn_pnbuf, ndp->ni_pathlen);
    402       1.88       dsl 	}
    403       1.97        ad 
    404      1.118  dholland 	vn_lock(state->namei_startdir, LK_EXCLUSIVE | LK_RETRY);
    405      1.117  dholland 
    406      1.117  dholland 	return 0;
    407      1.117  dholland }
    408      1.117  dholland 
    409      1.117  dholland /*
    410      1.117  dholland  * Undo namei_start: unlock and release the current lookup directory,
    411      1.117  dholland  * and discard the path buffer.
    412      1.117  dholland  */
    413      1.117  dholland static void
    414      1.117  dholland namei_end(struct namei_state *state)
    415      1.117  dholland {
    416      1.118  dholland 	vput(state->namei_startdir);
    417      1.117  dholland 	PNBUF_PUT(state->cnp->cn_pnbuf);
    418      1.117  dholland 	//state->cnp->cn_pnbuf = NULL; // not yet (just in case) (XXX)
    419      1.117  dholland }
    420      1.117  dholland 
    421      1.117  dholland /*
    422      1.117  dholland  * Check for being at a symlink.
    423      1.117  dholland  */
    424      1.117  dholland static inline int
    425      1.117  dholland namei_atsymlink(struct namei_state *state)
    426      1.117  dholland {
    427      1.117  dholland 	return (state->cnp->cn_flags & ISSYMLINK) != 0;
    428      1.117  dholland }
    429      1.117  dholland 
    430      1.117  dholland /*
    431      1.117  dholland  * Follow a symlink.
    432      1.117  dholland  */
    433      1.117  dholland static inline int
    434      1.117  dholland namei_follow(struct namei_state *state)
    435      1.117  dholland {
    436      1.117  dholland 	struct nameidata *ndp = state->ndp;
    437      1.117  dholland 	struct componentname *cnp = state->cnp;
    438      1.117  dholland 
    439      1.117  dholland 	struct lwp *self = curlwp;	/* thread doing namei() */
    440      1.117  dholland 	struct iovec aiov;		/* uio for reading symbolic links */
    441      1.117  dholland 	struct uio auio;
    442      1.117  dholland 	char *cp;			/* pointer into pathname argument */
    443      1.117  dholland 	size_t linklen;
    444      1.117  dholland 	int error;
    445      1.117  dholland 
    446      1.117  dholland 	if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
    447      1.117  dholland 		return ELOOP;
    448      1.117  dholland 	}
    449      1.117  dholland 	if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
    450      1.117  dholland 		error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred);
    451      1.117  dholland 		if (error != 0)
    452      1.117  dholland 			return error;
    453      1.117  dholland 	}
    454      1.117  dholland 	if (ndp->ni_pathlen > 1)
    455      1.117  dholland 		cp = PNBUF_GET();
    456      1.117  dholland 	else
    457      1.117  dholland 		cp = cnp->cn_pnbuf;
    458      1.117  dholland 	aiov.iov_base = cp;
    459      1.117  dholland 	aiov.iov_len = MAXPATHLEN;
    460      1.117  dholland 	auio.uio_iov = &aiov;
    461      1.117  dholland 	auio.uio_iovcnt = 1;
    462      1.117  dholland 	auio.uio_offset = 0;
    463      1.117  dholland 	auio.uio_rw = UIO_READ;
    464      1.117  dholland 	auio.uio_resid = MAXPATHLEN;
    465      1.117  dholland 	UIO_SETUP_SYSSPACE(&auio);
    466      1.117  dholland 	error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
    467      1.117  dholland 	if (error) {
    468      1.117  dholland badlink:
    469      1.117  dholland 		if (ndp->ni_pathlen > 1)
    470      1.117  dholland 			PNBUF_PUT(cp);
    471      1.117  dholland 		return error;
    472      1.117  dholland 	}
    473      1.117  dholland 	linklen = MAXPATHLEN - auio.uio_resid;
    474      1.117  dholland 	if (linklen == 0) {
    475      1.117  dholland 		error = ENOENT;
    476      1.117  dholland 		goto badlink;
    477      1.117  dholland 	}
    478      1.117  dholland 
    479      1.117  dholland 	/*
    480      1.117  dholland 	 * Do symlink substitution, if appropriate, and
    481      1.117  dholland 	 * check length for potential overflow.
    482      1.117  dholland 	 */
    483      1.117  dholland 	if ((vfs_magiclinks &&
    484      1.117  dholland 	     symlink_magic(self->l_proc, cp, &linklen)) ||
    485      1.117  dholland 	    (linklen + ndp->ni_pathlen >= MAXPATHLEN)) {
    486      1.117  dholland 		error = ENAMETOOLONG;
    487      1.117  dholland 		goto badlink;
    488      1.117  dholland 	}
    489      1.117  dholland 	if (ndp->ni_pathlen > 1) {
    490      1.117  dholland 		memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
    491      1.117  dholland 		PNBUF_PUT(cnp->cn_pnbuf);
    492      1.117  dholland 		cnp->cn_pnbuf = cp;
    493      1.117  dholland 	} else
    494      1.117  dholland 		cnp->cn_pnbuf[linklen] = '\0';
    495      1.117  dholland 	ndp->ni_pathlen += linklen;
    496      1.117  dholland 	vput(ndp->ni_vp);
    497      1.118  dholland 	state->namei_startdir = ndp->ni_dvp;
    498      1.117  dholland 
    499      1.117  dholland 	/*
    500      1.117  dholland 	 * Check if root directory should replace current directory.
    501      1.117  dholland 	 */
    502      1.117  dholland 	if (cnp->cn_pnbuf[0] == '/') {
    503      1.118  dholland 		vput(state->namei_startdir);
    504      1.117  dholland 		/* Keep absolute symbolic links inside emulation root */
    505      1.118  dholland 		state->namei_startdir = ndp->ni_erootdir;
    506      1.118  dholland 		if (state->namei_startdir == NULL || (cnp->cn_pnbuf[1] == '.'
    507      1.117  dholland 					  && cnp->cn_pnbuf[2] == '.'
    508      1.117  dholland 					  && cnp->cn_pnbuf[3] == '/')) {
    509      1.117  dholland 			ndp->ni_erootdir = NULL;
    510      1.118  dholland 			state->namei_startdir = ndp->ni_rootdir;
    511      1.117  dholland 		}
    512      1.121     pooka 		vref(state->namei_startdir);
    513      1.118  dholland 		vn_lock(state->namei_startdir, LK_EXCLUSIVE | LK_RETRY);
    514      1.117  dholland 	}
    515      1.117  dholland 
    516      1.117  dholland 	return 0;
    517      1.117  dholland }
    518      1.117  dholland 
    519      1.117  dholland //////////////////////////////
    520      1.117  dholland 
    521      1.117  dholland static int
    522      1.117  dholland do_namei(struct namei_state *state)
    523      1.117  dholland {
    524      1.117  dholland 	int error;
    525      1.117  dholland 
    526      1.117  dholland 	struct nameidata *ndp = state->ndp;
    527      1.117  dholland 	struct componentname *cnp = state->cnp;
    528      1.117  dholland 
    529      1.117  dholland 	KASSERT(cnp == &ndp->ni_cnd);
    530      1.117  dholland 
    531      1.117  dholland 	namei_start1(state);
    532      1.117  dholland 
    533      1.117  dholland     emul_retry:
    534      1.117  dholland 
    535      1.117  dholland 	error = namei_start2(state);
    536      1.117  dholland 	if (error) {
    537      1.117  dholland 		return error;
    538      1.117  dholland 	}
    539      1.117  dholland 
    540       1.85       dsl 	/* Loop through symbolic links */
    541       1.10       cgd 	for (;;) {
    542      1.118  dholland 		if (state->namei_startdir->v_mount == NULL) {
    543       1.45       erh 			/* Give up if the directory is no longer mounted */
    544      1.117  dholland 			namei_end(state);
    545       1.45       erh 			return (ENOENT);
    546       1.45       erh 		}
    547       1.12   mycroft 		cnp->cn_nameptr = cnp->cn_pnbuf;
    548      1.118  dholland 		ndp->ni_startdir = state->namei_startdir;
    549      1.119  dholland 		error = do_lookup(state);
    550       1.73       chs 		if (error != 0) {
    551      1.117  dholland 			/* XXX this should use namei_end() */
    552       1.73       chs 			if (ndp->ni_dvp) {
    553       1.73       chs 				vput(ndp->ni_dvp);
    554       1.73       chs 			}
    555       1.90       dsl 			if (ndp->ni_erootdir != NULL) {
    556       1.85       dsl 				/* Retry the whole thing from the normal root */
    557       1.85       dsl 				cnp->cn_flags &= ~TRYEMULROOT;
    558       1.85       dsl 				goto emul_retry;
    559       1.85       dsl 			}
    560       1.35   thorpej 			PNBUF_PUT(cnp->cn_pnbuf);
    561       1.10       cgd 			return (error);
    562       1.10       cgd 		}
    563       1.73       chs 
    564       1.10       cgd 		/*
    565       1.10       cgd 		 * Check for symbolic link
    566       1.10       cgd 		 */
    567      1.117  dholland 		if (namei_atsymlink(state)) {
    568      1.117  dholland 			error = namei_follow(state);
    569      1.117  dholland 			if (error) {
    570      1.117  dholland 				KASSERT(ndp->ni_dvp != ndp->ni_vp);
    571      1.117  dholland 				vput(ndp->ni_dvp);
    572      1.117  dholland 				vput(ndp->ni_vp);
    573      1.117  dholland 				ndp->ni_vp = NULL;
    574       1.35   thorpej 				PNBUF_PUT(cnp->cn_pnbuf);
    575      1.117  dholland 				return error;
    576      1.114      yamt 			}
    577       1.10       cgd 		}
    578      1.117  dholland 		else {
    579       1.10       cgd 			break;
    580       1.10       cgd 		}
    581      1.117  dholland 	}
    582       1.73       chs 
    583      1.117  dholland 	/*
    584      1.117  dholland 	 * Done
    585      1.117  dholland 	 */
    586       1.73       chs 
    587      1.117  dholland 	if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
    588      1.117  dholland 		if (ndp->ni_dvp == ndp->ni_vp) {
    589      1.117  dholland 			vrele(ndp->ni_dvp);
    590      1.117  dholland 		} else {
    591      1.117  dholland 			vput(ndp->ni_dvp);
    592       1.23   mycroft 		}
    593       1.10       cgd 	}
    594      1.117  dholland 	if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) {
    595      1.117  dholland 		PNBUF_PUT(cnp->cn_pnbuf);
    596      1.117  dholland #if defined(DIAGNOSTIC)
    597      1.117  dholland 		cnp->cn_pnbuf = NULL;
    598      1.117  dholland #endif /* defined(DIAGNOSTIC) */
    599      1.117  dholland 	} else {
    600      1.117  dholland 		cnp->cn_flags |= HASBUF;
    601      1.117  dholland 	}
    602      1.117  dholland 
    603      1.117  dholland 	return 0;
    604      1.117  dholland }
    605      1.117  dholland 
    606      1.117  dholland int
    607      1.117  dholland namei(struct nameidata *ndp)
    608      1.117  dholland {
    609      1.117  dholland 	struct namei_state state;
    610      1.117  dholland 	int error;
    611      1.117  dholland 
    612      1.117  dholland 	namei_init(&state, ndp);
    613      1.117  dholland 	error = do_namei(&state);
    614      1.117  dholland 	namei_cleanup(&state);
    615      1.117  dholland 
    616      1.117  dholland 	return error;
    617       1.10       cgd }
    618       1.10       cgd 
    619       1.10       cgd /*
    620       1.39     lukem  * Determine the namei hash (for cn_hash) for name.
    621       1.39     lukem  * If *ep != NULL, hash from name to ep-1.
    622       1.39     lukem  * If *ep == NULL, hash from name until the first NUL or '/', and
    623       1.39     lukem  * return the location of this termination character in *ep.
    624       1.39     lukem  *
    625       1.39     lukem  * This function returns an equivalent hash to the MI hash32_strn().
    626       1.39     lukem  * The latter isn't used because in the *ep == NULL case, determining
    627       1.39     lukem  * the length of the string to the first NUL or `/' and then calling
    628       1.39     lukem  * hash32_strn() involves unnecessary double-handling of the data.
    629       1.39     lukem  */
    630       1.39     lukem uint32_t
    631       1.39     lukem namei_hash(const char *name, const char **ep)
    632       1.39     lukem {
    633       1.39     lukem 	uint32_t	hash;
    634       1.39     lukem 
    635       1.39     lukem 	hash = HASH32_STR_INIT;
    636       1.39     lukem 	if (*ep != NULL) {
    637       1.39     lukem 		for (; name < *ep; name++)
    638       1.59  christos 			hash = hash * 33 + *(const uint8_t *)name;
    639       1.39     lukem 	} else {
    640       1.39     lukem 		for (; *name != '\0' && *name != '/'; name++)
    641       1.59  christos 			hash = hash * 33 + *(const uint8_t *)name;
    642       1.39     lukem 		*ep = name;
    643       1.39     lukem 	}
    644       1.39     lukem 	return (hash + (hash >> 5));
    645       1.39     lukem }
    646       1.39     lukem 
    647       1.39     lukem /*
    648       1.10       cgd  * Search a pathname.
    649       1.10       cgd  * This is a very central and rather complicated routine.
    650       1.10       cgd  *
    651       1.10       cgd  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
    652       1.10       cgd  * The starting directory is taken from ni_startdir. The pathname is
    653       1.10       cgd  * descended until done, or a symbolic link is encountered. The variable
    654       1.10       cgd  * ni_more is clear if the path is completed; it is set to one if a
    655       1.10       cgd  * symbolic link needing interpretation is encountered.
    656       1.10       cgd  *
    657       1.10       cgd  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
    658       1.10       cgd  * whether the name is to be looked up, created, renamed, or deleted.
    659       1.10       cgd  * When CREATE, RENAME, or DELETE is specified, information usable in
    660       1.10       cgd  * creating, renaming, or deleting a directory entry may be calculated.
    661       1.10       cgd  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
    662       1.79     pooka  * locked.  Otherwise the parent directory is not returned. If the target
    663       1.79     pooka  * of the pathname exists and LOCKLEAF is or'ed into the flag the target
    664       1.79     pooka  * is returned locked, otherwise it is returned unlocked.  When creating
    665       1.79     pooka  * or renaming and LOCKPARENT is specified, the target may not be ".".
    666       1.79     pooka  * When deleting and LOCKPARENT is specified, the target may be ".".
    667       1.56     perry  *
    668       1.10       cgd  * Overall outline of lookup:
    669       1.10       cgd  *
    670       1.10       cgd  * dirloop:
    671       1.10       cgd  *	identify next component of name at ndp->ni_ptr
    672       1.10       cgd  *	handle degenerate case where name is null string
    673       1.10       cgd  *	if .. and crossing mount points and on mounted filesys, find parent
    674       1.10       cgd  *	call VOP_LOOKUP routine for next component name
    675       1.79     pooka  *	    directory vnode returned in ni_dvp, locked.
    676       1.10       cgd  *	    component vnode returned in ni_vp (if it exists), locked.
    677       1.10       cgd  *	if result vnode is mounted on and crossing mount points,
    678       1.10       cgd  *	    find mounted on vnode
    679       1.10       cgd  *	if more components of name, do next level at dirloop
    680       1.10       cgd  *	return the answer in ni_vp, locked if LOCKLEAF set
    681       1.10       cgd  *	    if LOCKPARENT set, return locked parent in ni_dvp
    682       1.10       cgd  */
    683      1.118  dholland 
    684      1.118  dholland /*
    685      1.118  dholland  * Begin lookup().
    686      1.118  dholland  */
    687      1.118  dholland static int
    688      1.118  dholland lookup_start(struct namei_state *state)
    689       1.10       cgd {
    690       1.33  augustss 	const char *cp;			/* pointer into pathname argument */
    691      1.118  dholland 
    692      1.118  dholland 	struct componentname *cnp = state->cnp;
    693      1.118  dholland 	struct nameidata *ndp = state->ndp;
    694      1.118  dholland 
    695      1.118  dholland 	KASSERT(cnp == &ndp->ni_cnd);
    696      1.118  dholland 
    697      1.118  dholland 	state->lookup_alldone = 0;
    698      1.118  dholland 	state->dp = NULL;
    699       1.10       cgd 
    700       1.10       cgd 	/*
    701       1.10       cgd 	 * Setup: break out flag bits into variables.
    702       1.10       cgd 	 */
    703      1.118  dholland 	state->docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
    704       1.78     pooka 	if (cnp->cn_nameiop == DELETE)
    705      1.118  dholland 		state->docache = 0;
    706      1.118  dholland 	state->rdonly = cnp->cn_flags & RDONLY;
    707       1.10       cgd 	ndp->ni_dvp = NULL;
    708       1.12   mycroft 	cnp->cn_flags &= ~ISSYMLINK;
    709      1.118  dholland 	state->dp = ndp->ni_startdir;
    710       1.10       cgd 	ndp->ni_startdir = NULLVP;
    711       1.10       cgd 
    712       1.23   mycroft 	/*
    713       1.23   mycroft 	 * If we have a leading string of slashes, remove them, and just make
    714       1.23   mycroft 	 * sure the current node is a directory.
    715       1.23   mycroft 	 */
    716       1.23   mycroft 	cp = cnp->cn_nameptr;
    717       1.23   mycroft 	if (*cp == '/') {
    718       1.23   mycroft 		do {
    719       1.23   mycroft 			cp++;
    720       1.23   mycroft 		} while (*cp == '/');
    721       1.23   mycroft 		ndp->ni_pathlen -= cp - cnp->cn_nameptr;
    722       1.23   mycroft 		cnp->cn_nameptr = cp;
    723       1.23   mycroft 
    724      1.118  dholland 		if (state->dp->v_type != VDIR) {
    725      1.118  dholland 			vput(state->dp);
    726      1.118  dholland 			return ENOTDIR;
    727       1.23   mycroft 		}
    728       1.23   mycroft 
    729       1.23   mycroft 		/*
    730       1.23   mycroft 		 * If we've exhausted the path name, then just return the
    731       1.87       dsl 		 * current node.
    732       1.23   mycroft 		 */
    733       1.23   mycroft 		if (cnp->cn_nameptr[0] == '\0') {
    734      1.118  dholland 			ndp->ni_vp = state->dp;
    735       1.23   mycroft 			cnp->cn_flags |= ISLASTCN;
    736      1.118  dholland 
    737      1.118  dholland 			/* bleh */
    738      1.118  dholland 			state->lookup_alldone = 1;
    739      1.118  dholland 			return 0;
    740       1.23   mycroft 		}
    741       1.23   mycroft 	}
    742       1.23   mycroft 
    743      1.118  dholland 	return 0;
    744      1.118  dholland }
    745      1.118  dholland 
    746      1.118  dholland static int
    747      1.118  dholland lookup_parsepath(struct namei_state *state)
    748      1.118  dholland {
    749      1.118  dholland 	const char *cp;			/* pointer into pathname argument */
    750      1.118  dholland 
    751      1.118  dholland 	struct componentname *cnp = state->cnp;
    752      1.118  dholland 	struct nameidata *ndp = state->ndp;
    753      1.118  dholland 
    754      1.118  dholland 	KASSERT(cnp == &ndp->ni_cnd);
    755      1.118  dholland 
    756       1.10       cgd 	/*
    757       1.10       cgd 	 * Search a new directory.
    758       1.10       cgd 	 *
    759       1.12   mycroft 	 * The cn_hash value is for use by vfs_cache.
    760       1.10       cgd 	 * The last component of the filename is left accessible via
    761       1.12   mycroft 	 * cnp->cn_nameptr for callers that need the name. Callers needing
    762       1.10       cgd 	 * the name set the SAVENAME flag. When done, they assume
    763       1.10       cgd 	 * responsibility for freeing the pathname buffer.
    764       1.73       chs 	 *
    765       1.73       chs 	 * At this point, our only vnode state is that "dp" is held and locked.
    766       1.10       cgd 	 */
    767       1.12   mycroft 	cnp->cn_consume = 0;
    768       1.39     lukem 	cp = NULL;
    769       1.39     lukem 	cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp);
    770       1.12   mycroft 	cnp->cn_namelen = cp - cnp->cn_nameptr;
    771       1.12   mycroft 	if (cnp->cn_namelen > NAME_MAX) {
    772      1.118  dholland 		vput(state->dp);
    773       1.77       chs 		ndp->ni_dvp = NULL;
    774      1.118  dholland 		return ENAMETOOLONG;
    775       1.10       cgd 	}
    776       1.10       cgd #ifdef NAMEI_DIAGNOSTIC
    777       1.10       cgd 	{ char c = *cp;
    778       1.41     soren 	*(char *)cp = '\0';
    779       1.19  christos 	printf("{%s}: ", cnp->cn_nameptr);
    780       1.41     soren 	*(char *)cp = c; }
    781       1.52      yamt #endif /* NAMEI_DIAGNOSTIC */
    782       1.12   mycroft 	ndp->ni_pathlen -= cnp->cn_namelen;
    783       1.10       cgd 	ndp->ni_next = cp;
    784       1.23   mycroft 	/*
    785       1.23   mycroft 	 * If this component is followed by a slash, then move the pointer to
    786       1.23   mycroft 	 * the next component forward, and remember that this component must be
    787       1.23   mycroft 	 * a directory.
    788       1.23   mycroft 	 */
    789       1.23   mycroft 	if (*cp == '/') {
    790       1.23   mycroft 		do {
    791       1.23   mycroft 			cp++;
    792       1.23   mycroft 		} while (*cp == '/');
    793      1.118  dholland 		state->slashes = cp - ndp->ni_next;
    794      1.118  dholland 		ndp->ni_pathlen -= state->slashes;
    795       1.23   mycroft 		ndp->ni_next = cp;
    796       1.23   mycroft 		cnp->cn_flags |= REQUIREDIR;
    797       1.23   mycroft 	} else {
    798      1.118  dholland 		state->slashes = 0;
    799       1.23   mycroft 		cnp->cn_flags &= ~REQUIREDIR;
    800       1.23   mycroft 	}
    801       1.23   mycroft 	/*
    802       1.23   mycroft 	 * We do special processing on the last component, whether or not it's
    803       1.23   mycroft 	 * a directory.  Cache all intervening lookups, but not the final one.
    804       1.23   mycroft 	 */
    805       1.23   mycroft 	if (*cp == '\0') {
    806      1.118  dholland 		if (state->docache)
    807       1.23   mycroft 			cnp->cn_flags |= MAKEENTRY;
    808       1.23   mycroft 		else
    809       1.23   mycroft 			cnp->cn_flags &= ~MAKEENTRY;
    810       1.23   mycroft 		cnp->cn_flags |= ISLASTCN;
    811       1.23   mycroft 	} else {
    812       1.23   mycroft 		cnp->cn_flags |= MAKEENTRY;
    813       1.23   mycroft 		cnp->cn_flags &= ~ISLASTCN;
    814       1.23   mycroft 	}
    815       1.12   mycroft 	if (cnp->cn_namelen == 2 &&
    816       1.12   mycroft 	    cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
    817       1.12   mycroft 		cnp->cn_flags |= ISDOTDOT;
    818       1.12   mycroft 	else
    819       1.12   mycroft 		cnp->cn_flags &= ~ISDOTDOT;
    820       1.10       cgd 
    821      1.118  dholland 	return 0;
    822      1.118  dholland }
    823      1.118  dholland 
    824      1.118  dholland static int
    825      1.118  dholland lookup_once(struct namei_state *state)
    826      1.118  dholland {
    827      1.118  dholland 	struct vnode *tdp;		/* saved dp */
    828      1.118  dholland 	struct mount *mp;		/* mount table entry */
    829      1.118  dholland 	struct lwp *l = curlwp;
    830      1.118  dholland 	int error;
    831      1.118  dholland 
    832      1.118  dholland 	struct componentname *cnp = state->cnp;
    833      1.118  dholland 	struct nameidata *ndp = state->ndp;
    834      1.118  dholland 
    835      1.118  dholland 	KASSERT(cnp == &ndp->ni_cnd);
    836      1.118  dholland 
    837       1.10       cgd 	/*
    838       1.10       cgd 	 * Handle "..": two special cases.
    839       1.10       cgd 	 * 1. If at root directory (e.g. after chroot)
    840       1.12   mycroft 	 *    or at absolute root directory
    841       1.10       cgd 	 *    then ignore it so can't get out.
    842       1.85       dsl 	 * 1a. If at the root of the emulation filesystem go to the real
    843       1.85       dsl 	 *    root. So "/../<path>" is always absolute.
    844       1.85       dsl 	 * 1b. If we have somehow gotten out of a jail, warn
    845       1.40  wrstuden 	 *    and also ignore it so we can't get farther out.
    846       1.10       cgd 	 * 2. If this vnode is the root of a mounted
    847       1.10       cgd 	 *    filesystem, then replace it with the
    848       1.10       cgd 	 *    vnode which was mounted on so we take the
    849       1.10       cgd 	 *    .. in the other file system.
    850       1.10       cgd 	 */
    851       1.12   mycroft 	if (cnp->cn_flags & ISDOTDOT) {
    852       1.64  christos 		struct proc *p = l->l_proc;
    853       1.64  christos 
    854       1.10       cgd 		for (;;) {
    855      1.118  dholland 			if (state->dp == ndp->ni_rootdir || state->dp == rootvnode) {
    856      1.118  dholland 				ndp->ni_dvp = state->dp;
    857      1.118  dholland 				ndp->ni_vp = state->dp;
    858      1.121     pooka 				vref(state->dp);
    859      1.118  dholland 				return 0;
    860       1.40  wrstuden 			}
    861       1.40  wrstuden 			if (ndp->ni_rootdir != rootvnode) {
    862       1.40  wrstuden 				int retval;
    863       1.73       chs 
    864  1.121.2.1  uebayasi 				VOP_UNLOCK(state->dp);
    865      1.118  dholland 				retval = vn_isunder(state->dp, ndp->ni_rootdir, l);
    866      1.118  dholland 				vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
    867       1.40  wrstuden 				if (!retval) {
    868       1.40  wrstuden 				    /* Oops! We got out of jail! */
    869       1.40  wrstuden 				    log(LOG_WARNING,
    870       1.40  wrstuden 					"chrooted pid %d uid %d (%s) "
    871       1.40  wrstuden 					"detected outside of its chroot\n",
    872       1.71        ad 					p->p_pid, kauth_cred_geteuid(l->l_cred),
    873       1.64  christos 					p->p_comm);
    874       1.40  wrstuden 				    /* Put us at the jail root. */
    875      1.118  dholland 				    vput(state->dp);
    876      1.118  dholland 				    state->dp = ndp->ni_rootdir;
    877      1.118  dholland 				    ndp->ni_dvp = state->dp;
    878      1.118  dholland 				    ndp->ni_vp = state->dp;
    879      1.121     pooka 				    vref(state->dp);
    880      1.121     pooka 				    vref(state->dp);
    881      1.118  dholland 				    vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
    882      1.118  dholland 				    return 0;
    883       1.40  wrstuden 				}
    884       1.10       cgd 			}
    885      1.118  dholland 			if ((state->dp->v_vflag & VV_ROOT) == 0 ||
    886       1.12   mycroft 			    (cnp->cn_flags & NOCROSSMOUNT))
    887       1.10       cgd 				break;
    888      1.118  dholland 			tdp = state->dp;
    889      1.118  dholland 			state->dp = state->dp->v_mount->mnt_vnodecovered;
    890       1.10       cgd 			vput(tdp);
    891      1.121     pooka 			vref(state->dp);
    892      1.118  dholland 			vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
    893       1.10       cgd 		}
    894       1.10       cgd 	}
    895       1.10       cgd 
    896       1.10       cgd 	/*
    897       1.10       cgd 	 * We now have a segment name to search for, and a directory to search.
    898       1.73       chs 	 * Again, our only vnode state is that "dp" is held and locked.
    899       1.10       cgd 	 */
    900       1.12   mycroft unionlookup:
    901      1.118  dholland 	ndp->ni_dvp = state->dp;
    902       1.26      fvdl 	ndp->ni_vp = NULL;
    903      1.118  dholland 	error = VOP_LOOKUP(state->dp, &ndp->ni_vp, cnp);
    904       1.73       chs 	if (error != 0) {
    905       1.10       cgd #ifdef DIAGNOSTIC
    906       1.10       cgd 		if (ndp->ni_vp != NULL)
    907       1.43  christos 			panic("leaf `%s' should be empty", cnp->cn_nameptr);
    908       1.52      yamt #endif /* DIAGNOSTIC */
    909       1.10       cgd #ifdef NAMEI_DIAGNOSTIC
    910       1.19  christos 		printf("not found\n");
    911       1.52      yamt #endif /* NAMEI_DIAGNOSTIC */
    912       1.12   mycroft 		if ((error == ENOENT) &&
    913      1.118  dholland 		    (state->dp->v_vflag & VV_ROOT) &&
    914      1.118  dholland 		    (state->dp->v_mount->mnt_flag & MNT_UNION)) {
    915      1.118  dholland 			tdp = state->dp;
    916      1.118  dholland 			state->dp = state->dp->v_mount->mnt_vnodecovered;
    917       1.73       chs 			vput(tdp);
    918      1.121     pooka 			vref(state->dp);
    919      1.118  dholland 			vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
    920       1.12   mycroft 			goto unionlookup;
    921       1.10       cgd 		}
    922       1.12   mycroft 
    923       1.10       cgd 		if (error != EJUSTRETURN)
    924      1.118  dholland 			return error;
    925       1.73       chs 
    926       1.10       cgd 		/*
    927       1.23   mycroft 		 * If this was not the last component, or there were trailing
    928       1.51  christos 		 * slashes, and we are not going to create a directory,
    929       1.51  christos 		 * then the name must exist.
    930       1.23   mycroft 		 */
    931       1.51  christos 		if ((cnp->cn_flags & (REQUIREDIR | CREATEDIR)) == REQUIREDIR) {
    932      1.118  dholland 			return ENOENT;
    933       1.23   mycroft 		}
    934       1.73       chs 
    935       1.23   mycroft 		/*
    936       1.10       cgd 		 * If creating and at end of pathname, then can consider
    937       1.10       cgd 		 * allowing file to be created.
    938       1.10       cgd 		 */
    939      1.118  dholland 		if (state->rdonly) {
    940      1.118  dholland 			return EROFS;
    941       1.10       cgd 		}
    942       1.73       chs 
    943       1.10       cgd 		/*
    944       1.10       cgd 		 * We return with ni_vp NULL to indicate that the entry
    945       1.10       cgd 		 * doesn't currently exist, leaving a pointer to the
    946       1.69    rumble 		 * (possibly locked) directory vnode in ndp->ni_dvp.
    947       1.10       cgd 		 */
    948       1.12   mycroft 		if (cnp->cn_flags & SAVESTART) {
    949       1.10       cgd 			ndp->ni_startdir = ndp->ni_dvp;
    950      1.121     pooka 			vref(ndp->ni_startdir);
    951       1.10       cgd 		}
    952      1.118  dholland 		state->lookup_alldone = 1;
    953       1.10       cgd 		return (0);
    954       1.10       cgd 	}
    955       1.10       cgd #ifdef NAMEI_DIAGNOSTIC
    956       1.19  christos 	printf("found\n");
    957       1.52      yamt #endif /* NAMEI_DIAGNOSTIC */
    958       1.10       cgd 
    959       1.12   mycroft 	/*
    960       1.23   mycroft 	 * Take into account any additional components consumed by the
    961       1.23   mycroft 	 * underlying filesystem.  This will include any trailing slashes after
    962       1.23   mycroft 	 * the last component consumed.
    963       1.12   mycroft 	 */
    964       1.12   mycroft 	if (cnp->cn_consume > 0) {
    965      1.118  dholland 		ndp->ni_pathlen -= cnp->cn_consume - state->slashes;
    966      1.118  dholland 		ndp->ni_next += cnp->cn_consume - state->slashes;
    967       1.12   mycroft 		cnp->cn_consume = 0;
    968       1.23   mycroft 		if (ndp->ni_next[0] == '\0')
    969       1.23   mycroft 			cnp->cn_flags |= ISLASTCN;
    970       1.12   mycroft 	}
    971       1.12   mycroft 
    972      1.118  dholland 	state->dp = ndp->ni_vp;
    973       1.73       chs 
    974       1.73       chs 	/*
    975      1.118  dholland 	 * "state->dp" and "ndp->ni_dvp" are both locked and held,
    976       1.73       chs 	 * and may be the same vnode.
    977       1.73       chs 	 */
    978       1.73       chs 
    979       1.10       cgd 	/*
    980       1.10       cgd 	 * Check to see if the vnode has been mounted on;
    981       1.10       cgd 	 * if so find the root of the mounted file system.
    982       1.10       cgd 	 */
    983      1.118  dholland 	while (state->dp->v_type == VDIR && (mp = state->dp->v_mountedhere) &&
    984       1.12   mycroft 	       (cnp->cn_flags & NOCROSSMOUNT) == 0) {
    985      1.108        ad 		error = vfs_busy(mp, NULL);
    986      1.107        ad 		if (error != 0) {
    987      1.118  dholland 			vput(state->dp);
    988      1.118  dholland 			return error;
    989      1.107        ad 		}
    990      1.118  dholland 		KASSERT(ndp->ni_dvp != state->dp);
    991  1.121.2.1  uebayasi 		VOP_UNLOCK(ndp->ni_dvp);
    992      1.118  dholland 		vput(state->dp);
    993       1.47   thorpej 		error = VFS_ROOT(mp, &tdp);
    994      1.106        ad 		vfs_unbusy(mp, false, NULL);
    995       1.32  wrstuden 		if (error) {
    996       1.77       chs 			vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
    997      1.118  dholland 			return error;
    998       1.32  wrstuden 		}
    999  1.121.2.1  uebayasi 		VOP_UNLOCK(tdp);
   1000      1.118  dholland 		ndp->ni_vp = state->dp = tdp;
   1001       1.77       chs 		vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
   1002       1.77       chs 		vn_lock(ndp->ni_vp, LK_EXCLUSIVE | LK_RETRY);
   1003       1.14   mycroft 	}
   1004       1.14   mycroft 
   1005      1.118  dholland 	return 0;
   1006      1.118  dholland }
   1007      1.118  dholland 
   1008      1.118  dholland static int
   1009      1.118  dholland do_lookup(struct namei_state *state)
   1010      1.118  dholland {
   1011      1.118  dholland 	int error = 0;
   1012      1.118  dholland 
   1013      1.118  dholland 	struct componentname *cnp = state->cnp;
   1014      1.118  dholland 	struct nameidata *ndp = state->ndp;
   1015      1.118  dholland 
   1016      1.118  dholland 	KASSERT(cnp == &ndp->ni_cnd);
   1017      1.118  dholland 
   1018      1.118  dholland 	error = lookup_start(state);
   1019      1.118  dholland 	if (error) {
   1020      1.118  dholland 		goto bad;
   1021      1.118  dholland 	}
   1022      1.118  dholland 	// XXX: this case should not be necessary given proper handling
   1023      1.118  dholland 	// of slashes elsewhere.
   1024      1.118  dholland 	if (state->lookup_alldone) {
   1025      1.118  dholland 		goto terminal;
   1026      1.118  dholland 	}
   1027      1.118  dholland 
   1028      1.118  dholland dirloop:
   1029      1.118  dholland 	error = lookup_parsepath(state);
   1030      1.118  dholland 	if (error) {
   1031      1.118  dholland 		goto bad;
   1032      1.118  dholland 	}
   1033      1.118  dholland 
   1034      1.118  dholland 	error = lookup_once(state);
   1035      1.118  dholland 	if (error) {
   1036      1.118  dholland 		goto bad;
   1037      1.118  dholland 	}
   1038      1.118  dholland 	// XXX ought to be able to avoid this case too
   1039      1.118  dholland 	if (state->lookup_alldone) {
   1040      1.118  dholland 		/* this should NOT be "goto terminal;" */
   1041      1.118  dholland 		return 0;
   1042      1.118  dholland 	}
   1043      1.118  dholland 
   1044       1.14   mycroft 	/*
   1045       1.23   mycroft 	 * Check for symbolic link.  Back up over any slashes that we skipped,
   1046       1.23   mycroft 	 * as we will need them again.
   1047       1.14   mycroft 	 */
   1048      1.118  dholland 	if ((state->dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
   1049      1.118  dholland 		ndp->ni_pathlen += state->slashes;
   1050      1.118  dholland 		ndp->ni_next -= state->slashes;
   1051       1.14   mycroft 		cnp->cn_flags |= ISSYMLINK;
   1052       1.14   mycroft 		return (0);
   1053       1.10       cgd 	}
   1054       1.10       cgd 
   1055       1.23   mycroft 	/*
   1056       1.23   mycroft 	 * Check for directory, if the component was followed by a series of
   1057       1.23   mycroft 	 * slashes.
   1058       1.23   mycroft 	 */
   1059      1.118  dholland 	if ((state->dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
   1060       1.23   mycroft 		error = ENOTDIR;
   1061      1.118  dholland 		KASSERT(state->dp != ndp->ni_dvp);
   1062      1.118  dholland 		vput(state->dp);
   1063       1.73       chs 		goto bad;
   1064       1.23   mycroft 	}
   1065       1.23   mycroft 
   1066       1.10       cgd 	/*
   1067       1.23   mycroft 	 * Not a symbolic link.  If this was not the last component, then
   1068       1.23   mycroft 	 * continue at the next component, else return.
   1069       1.10       cgd 	 */
   1070       1.23   mycroft 	if (!(cnp->cn_flags & ISLASTCN)) {
   1071       1.12   mycroft 		cnp->cn_nameptr = ndp->ni_next;
   1072      1.118  dholland 		if (ndp->ni_dvp == state->dp) {
   1073       1.73       chs 			vrele(ndp->ni_dvp);
   1074       1.73       chs 		} else {
   1075       1.73       chs 			vput(ndp->ni_dvp);
   1076       1.73       chs 		}
   1077       1.10       cgd 		goto dirloop;
   1078       1.10       cgd 	}
   1079       1.23   mycroft 
   1080       1.23   mycroft terminal:
   1081      1.118  dholland 	if (state->dp == ndp->ni_erootdir) {
   1082       1.87       dsl 		/*
   1083       1.87       dsl 		 * We are about to return the emulation root.
   1084       1.87       dsl 		 * This isn't a good idea because code might repeatedly
   1085       1.87       dsl 		 * lookup ".." until the file matches that returned
   1086       1.87       dsl 		 * for "/" and loop forever.
   1087       1.87       dsl 		 * So convert it to the real root.
   1088       1.87       dsl 		 */
   1089      1.118  dholland 		if (ndp->ni_dvp == state->dp)
   1090      1.118  dholland 			vrele(state->dp);
   1091       1.87       dsl 		else
   1092       1.87       dsl 			if (ndp->ni_dvp != NULL)
   1093       1.87       dsl 				vput(ndp->ni_dvp);
   1094       1.87       dsl 		ndp->ni_dvp = NULL;
   1095      1.118  dholland 		vput(state->dp);
   1096      1.118  dholland 		state->dp = ndp->ni_rootdir;
   1097      1.121     pooka 		vref(state->dp);
   1098      1.118  dholland 		vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
   1099      1.118  dholland 		ndp->ni_vp = state->dp;
   1100       1.87       dsl 	}
   1101       1.87       dsl 
   1102       1.87       dsl 	/*
   1103       1.87       dsl 	 * If the caller requested the parent node (i.e.
   1104       1.87       dsl 	 * it's a CREATE, DELETE, or RENAME), and we don't have one
   1105       1.87       dsl 	 * (because this is the root directory), then we must fail.
   1106       1.87       dsl 	 */
   1107       1.87       dsl 	if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) {
   1108       1.87       dsl 		switch (cnp->cn_nameiop) {
   1109       1.87       dsl 		case CREATE:
   1110       1.87       dsl 			error = EEXIST;
   1111       1.87       dsl 			break;
   1112       1.87       dsl 		case DELETE:
   1113       1.87       dsl 		case RENAME:
   1114       1.87       dsl 			error = EBUSY;
   1115       1.87       dsl 			break;
   1116       1.87       dsl 		default:
   1117       1.87       dsl 			KASSERT(0);
   1118       1.87       dsl 		}
   1119      1.118  dholland 		vput(state->dp);
   1120       1.87       dsl 		goto bad;
   1121       1.87       dsl 	}
   1122       1.73       chs 
   1123       1.10       cgd 	/*
   1124       1.94     pooka 	 * Disallow directory write attempts on read-only lookups.
   1125       1.96     pooka 	 * Prefers EEXIST over EROFS for the CREATE case.
   1126       1.10       cgd 	 */
   1127      1.118  dholland 	if (state->rdonly &&
   1128       1.96     pooka 	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
   1129       1.26      fvdl 		error = EROFS;
   1130      1.118  dholland 		if (state->dp != ndp->ni_dvp) {
   1131      1.118  dholland 			vput(state->dp);
   1132       1.73       chs 		}
   1133       1.73       chs 		goto bad;
   1134       1.10       cgd 	}
   1135       1.23   mycroft 	if (ndp->ni_dvp != NULL) {
   1136       1.23   mycroft 		if (cnp->cn_flags & SAVESTART) {
   1137       1.23   mycroft 			ndp->ni_startdir = ndp->ni_dvp;
   1138      1.121     pooka 			vref(ndp->ni_startdir);
   1139       1.23   mycroft 		}
   1140       1.10       cgd 	}
   1141       1.73       chs 	if ((cnp->cn_flags & LOCKLEAF) == 0) {
   1142  1.121.2.1  uebayasi 		VOP_UNLOCK(state->dp);
   1143       1.73       chs 	}
   1144       1.10       cgd 	return (0);
   1145       1.10       cgd 
   1146       1.10       cgd bad:
   1147       1.10       cgd 	ndp->ni_vp = NULL;
   1148       1.12   mycroft 	return (error);
   1149       1.12   mycroft }
   1150       1.12   mycroft 
   1151       1.12   mycroft /*
   1152      1.119  dholland  * Externally visible interfaces used by nfsd (bletch, yuk, XXX)
   1153      1.119  dholland  *
   1154      1.119  dholland  * The "index" version differs from the "main" version in that it's
   1155      1.119  dholland  * called from a different place in a different context. For now I
   1156      1.119  dholland  * want to be able to shuffle code in from one call site without
   1157      1.119  dholland  * affecting the other.
   1158      1.118  dholland  */
   1159      1.119  dholland 
   1160      1.119  dholland int
   1161      1.120  dholland lookup_for_nfsd(struct nameidata *ndp, struct vnode *dp, int neverfollow)
   1162      1.119  dholland {
   1163      1.119  dholland 	struct namei_state state;
   1164      1.119  dholland 	int error;
   1165      1.119  dholland 
   1166      1.120  dholland 	struct iovec aiov;
   1167      1.120  dholland 	struct uio auio;
   1168      1.120  dholland 	int linklen;
   1169      1.120  dholland 	char *cp;
   1170      1.120  dholland 
   1171      1.119  dholland 	/* For now at least we don't have to frob the state */
   1172      1.119  dholland 	namei_init(&state, ndp);
   1173      1.120  dholland 
   1174      1.120  dholland 	/*
   1175      1.120  dholland 	 * BEGIN wodge of code from nfsd
   1176      1.120  dholland 	 */
   1177      1.120  dholland 
   1178      1.121     pooka 	vref(dp);
   1179      1.120  dholland 	vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
   1180      1.120  dholland 
   1181      1.120  dholland     for (;;) {
   1182      1.120  dholland 
   1183      1.120  dholland 	state.cnp->cn_nameptr = state.cnp->cn_pnbuf;
   1184      1.120  dholland 	state.ndp->ni_startdir = dp;
   1185      1.120  dholland 
   1186      1.120  dholland 	/*
   1187      1.120  dholland 	 * END wodge of code from nfsd
   1188      1.120  dholland 	 */
   1189      1.120  dholland 
   1190      1.119  dholland 	error = do_lookup(&state);
   1191      1.120  dholland 	if (error) {
   1192      1.120  dholland 		/* BEGIN from nfsd */
   1193      1.120  dholland 		if (ndp->ni_dvp) {
   1194      1.120  dholland 			vput(ndp->ni_dvp);
   1195      1.120  dholland 		}
   1196      1.120  dholland 		PNBUF_PUT(state.cnp->cn_pnbuf);
   1197      1.120  dholland 		/* END from nfsd */
   1198      1.120  dholland 		namei_cleanup(&state);
   1199      1.120  dholland 		return error;
   1200      1.120  dholland 	}
   1201      1.120  dholland 
   1202      1.120  dholland 	/*
   1203      1.120  dholland 	 * BEGIN wodge of code from nfsd
   1204      1.120  dholland 	 */
   1205      1.120  dholland 
   1206      1.120  dholland 	/*
   1207      1.120  dholland 	 * Check for encountering a symbolic link
   1208      1.120  dholland 	 */
   1209      1.120  dholland 	if ((state.cnp->cn_flags & ISSYMLINK) == 0) {
   1210      1.120  dholland 		if ((state.cnp->cn_flags & LOCKPARENT) == 0 && state.ndp->ni_dvp) {
   1211      1.120  dholland 			if (state.ndp->ni_dvp == state.ndp->ni_vp) {
   1212      1.120  dholland 				vrele(state.ndp->ni_dvp);
   1213      1.120  dholland 			} else {
   1214      1.120  dholland 				vput(state.ndp->ni_dvp);
   1215      1.120  dholland 			}
   1216      1.120  dholland 		}
   1217      1.120  dholland 		if (state.cnp->cn_flags & (SAVENAME | SAVESTART)) {
   1218      1.120  dholland 			state.cnp->cn_flags |= HASBUF;
   1219      1.120  dholland 		} else {
   1220      1.120  dholland 			PNBUF_PUT(state.cnp->cn_pnbuf);
   1221      1.120  dholland #if defined(DIAGNOSTIC)
   1222      1.120  dholland 			state.cnp->cn_pnbuf = NULL;
   1223      1.120  dholland #endif /* defined(DIAGNOSTIC) */
   1224      1.120  dholland 		}
   1225      1.120  dholland 		return (0);
   1226      1.120  dholland 	} else {
   1227      1.120  dholland 		if (neverfollow) {
   1228      1.120  dholland 			error = EINVAL;
   1229      1.120  dholland 			goto out;
   1230      1.120  dholland 		}
   1231      1.120  dholland 		if (state.ndp->ni_loopcnt++ >= MAXSYMLINKS) {
   1232      1.120  dholland 			error = ELOOP;
   1233      1.120  dholland 			goto out;
   1234      1.120  dholland 		}
   1235      1.120  dholland 		if (state.ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
   1236      1.120  dholland 			error = VOP_ACCESS(ndp->ni_vp, VEXEC, state.cnp->cn_cred);
   1237      1.120  dholland 			if (error != 0)
   1238      1.120  dholland 				goto out;
   1239      1.120  dholland 		}
   1240      1.120  dholland 		if (state.ndp->ni_pathlen > 1)
   1241      1.120  dholland 			cp = PNBUF_GET();
   1242      1.120  dholland 		else
   1243      1.120  dholland 			cp = state.cnp->cn_pnbuf;
   1244      1.120  dholland 		aiov.iov_base = cp;
   1245      1.120  dholland 		aiov.iov_len = MAXPATHLEN;
   1246      1.120  dholland 		auio.uio_iov = &aiov;
   1247      1.120  dholland 		auio.uio_iovcnt = 1;
   1248      1.120  dholland 		auio.uio_offset = 0;
   1249      1.120  dholland 		auio.uio_rw = UIO_READ;
   1250      1.120  dholland 		auio.uio_resid = MAXPATHLEN;
   1251      1.120  dholland 		UIO_SETUP_SYSSPACE(&auio);
   1252      1.120  dholland 		error = VOP_READLINK(ndp->ni_vp, &auio, state.cnp->cn_cred);
   1253      1.120  dholland 		if (error) {
   1254      1.120  dholland badlink:
   1255      1.120  dholland 			if (ndp->ni_pathlen > 1)
   1256      1.120  dholland 				PNBUF_PUT(cp);
   1257      1.120  dholland 			goto out;
   1258      1.120  dholland 		}
   1259      1.120  dholland 		linklen = MAXPATHLEN - auio.uio_resid;
   1260      1.120  dholland 		if (linklen == 0) {
   1261      1.120  dholland 			error = ENOENT;
   1262      1.120  dholland 			goto badlink;
   1263      1.120  dholland 		}
   1264      1.120  dholland 		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
   1265      1.120  dholland 			error = ENAMETOOLONG;
   1266      1.120  dholland 			goto badlink;
   1267      1.120  dholland 		}
   1268      1.120  dholland 		if (ndp->ni_pathlen > 1) {
   1269      1.120  dholland 			memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
   1270      1.120  dholland 			PNBUF_PUT(state.cnp->cn_pnbuf);
   1271      1.120  dholland 			state.cnp->cn_pnbuf = cp;
   1272      1.120  dholland 		} else
   1273      1.120  dholland 			state.cnp->cn_pnbuf[linklen] = '\0';
   1274      1.120  dholland 		state.ndp->ni_pathlen += linklen;
   1275      1.120  dholland 		vput(state.ndp->ni_vp);
   1276      1.120  dholland 		dp = state.ndp->ni_dvp;
   1277      1.120  dholland 
   1278      1.120  dholland 		/*
   1279      1.120  dholland 		 * Check if root directory should replace current directory.
   1280      1.120  dholland 		 */
   1281      1.120  dholland 		if (state.cnp->cn_pnbuf[0] == '/') {
   1282      1.120  dholland 			vput(dp);
   1283      1.120  dholland 			dp = ndp->ni_rootdir;
   1284      1.121     pooka 			vref(dp);
   1285      1.120  dholland 			vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
   1286      1.120  dholland 		}
   1287      1.120  dholland 	}
   1288      1.120  dholland 
   1289      1.120  dholland     }
   1290      1.120  dholland  out:
   1291      1.120  dholland 	vput(state.ndp->ni_vp);
   1292      1.120  dholland 	vput(state.ndp->ni_dvp);
   1293      1.120  dholland 	state.ndp->ni_vp = NULL;
   1294      1.120  dholland 	PNBUF_PUT(state.cnp->cn_pnbuf);
   1295      1.120  dholland 
   1296      1.120  dholland 	/*
   1297      1.120  dholland 	 * END wodge of code from nfsd
   1298      1.120  dholland 	 */
   1299      1.119  dholland 	namei_cleanup(&state);
   1300      1.119  dholland 
   1301      1.119  dholland 	return error;
   1302      1.119  dholland }
   1303      1.119  dholland 
   1304      1.118  dholland int
   1305      1.119  dholland lookup_for_nfsd_index(struct nameidata *ndp)
   1306      1.118  dholland {
   1307      1.118  dholland 	struct namei_state state;
   1308      1.118  dholland 	int error;
   1309      1.118  dholland 
   1310      1.118  dholland 	/* For now at least we don't have to frob the state */
   1311      1.118  dholland 	namei_init(&state, ndp);
   1312      1.118  dholland 	error = do_lookup(&state);
   1313      1.118  dholland 	namei_cleanup(&state);
   1314      1.118  dholland 
   1315      1.118  dholland 	return error;
   1316      1.118  dholland }
   1317      1.118  dholland 
   1318      1.118  dholland /*
   1319       1.12   mycroft  * Reacquire a path name component.
   1320       1.73       chs  * dvp is locked on entry and exit.
   1321       1.73       chs  * *vpp is locked on exit unless it's NULL.
   1322       1.12   mycroft  */
   1323       1.12   mycroft int
   1324       1.60   thorpej relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
   1325       1.12   mycroft {
   1326       1.12   mycroft 	int rdonly;			/* lookup read-only flag bit */
   1327       1.12   mycroft 	int error = 0;
   1328       1.52      yamt #ifdef DEBUG
   1329       1.81       chs 	uint32_t newhash;		/* DEBUG: check name hash */
   1330       1.41     soren 	const char *cp;			/* DEBUG: check name ptr/len */
   1331       1.52      yamt #endif /* DEBUG */
   1332       1.12   mycroft 
   1333       1.12   mycroft 	/*
   1334       1.12   mycroft 	 * Setup: break out flag bits into variables.
   1335       1.12   mycroft 	 */
   1336       1.12   mycroft 	rdonly = cnp->cn_flags & RDONLY;
   1337       1.12   mycroft 	cnp->cn_flags &= ~ISSYMLINK;
   1338       1.12   mycroft 
   1339       1.12   mycroft 	/*
   1340       1.12   mycroft 	 * Search a new directory.
   1341       1.12   mycroft 	 *
   1342       1.12   mycroft 	 * The cn_hash value is for use by vfs_cache.
   1343       1.12   mycroft 	 * The last component of the filename is left accessible via
   1344       1.12   mycroft 	 * cnp->cn_nameptr for callers that need the name. Callers needing
   1345       1.12   mycroft 	 * the name set the SAVENAME flag. When done, they assume
   1346       1.12   mycroft 	 * responsibility for freeing the pathname buffer.
   1347       1.12   mycroft 	 */
   1348       1.52      yamt #ifdef DEBUG
   1349       1.39     lukem 	cp = NULL;
   1350       1.39     lukem 	newhash = namei_hash(cnp->cn_nameptr, &cp);
   1351       1.81       chs 	if ((uint32_t)newhash != (uint32_t)cnp->cn_hash)
   1352       1.12   mycroft 		panic("relookup: bad hash");
   1353       1.12   mycroft 	if (cnp->cn_namelen != cp - cnp->cn_nameptr)
   1354       1.58  christos 		panic("relookup: bad len");
   1355       1.53      yamt 	while (*cp == '/')
   1356       1.53      yamt 		cp++;
   1357       1.12   mycroft 	if (*cp != 0)
   1358       1.12   mycroft 		panic("relookup: not last component");
   1359       1.52      yamt #endif /* DEBUG */
   1360       1.12   mycroft 
   1361       1.12   mycroft 	/*
   1362       1.12   mycroft 	 * Check for degenerate name (e.g. / or "")
   1363       1.12   mycroft 	 * which is a way of talking about a directory,
   1364       1.12   mycroft 	 * e.g. like "/." or ".".
   1365       1.12   mycroft 	 */
   1366       1.23   mycroft 	if (cnp->cn_nameptr[0] == '\0')
   1367       1.23   mycroft 		panic("relookup: null name");
   1368       1.12   mycroft 
   1369       1.12   mycroft 	if (cnp->cn_flags & ISDOTDOT)
   1370       1.58  christos 		panic("relookup: lookup on dot-dot");
   1371       1.12   mycroft 
   1372       1.12   mycroft 	/*
   1373       1.12   mycroft 	 * We now have a segment name to search for, and a directory to search.
   1374       1.12   mycroft 	 */
   1375       1.81       chs 	if ((error = VOP_LOOKUP(dvp, vpp, cnp)) != 0) {
   1376       1.12   mycroft #ifdef DIAGNOSTIC
   1377       1.12   mycroft 		if (*vpp != NULL)
   1378       1.43  christos 			panic("leaf `%s' should be empty", cnp->cn_nameptr);
   1379       1.12   mycroft #endif
   1380       1.12   mycroft 		if (error != EJUSTRETURN)
   1381       1.12   mycroft 			goto bad;
   1382       1.12   mycroft 	}
   1383       1.12   mycroft 
   1384       1.12   mycroft #ifdef DIAGNOSTIC
   1385       1.12   mycroft 	/*
   1386       1.12   mycroft 	 * Check for symbolic link
   1387       1.12   mycroft 	 */
   1388       1.81       chs 	if (*vpp && (*vpp)->v_type == VLNK && (cnp->cn_flags & FOLLOW))
   1389       1.58  christos 		panic("relookup: symlink found");
   1390       1.12   mycroft #endif
   1391       1.12   mycroft 
   1392       1.12   mycroft 	/*
   1393       1.94     pooka 	 * Check for read-only lookups.
   1394       1.12   mycroft 	 */
   1395       1.81       chs 	if (rdonly && cnp->cn_nameiop != LOOKUP) {
   1396       1.26      fvdl 		error = EROFS;
   1397       1.81       chs 		if (*vpp) {
   1398       1.81       chs 			vput(*vpp);
   1399       1.81       chs 		}
   1400       1.73       chs 		goto bad;
   1401       1.12   mycroft 	}
   1402       1.12   mycroft 	if (cnp->cn_flags & SAVESTART)
   1403      1.121     pooka 		vref(dvp);
   1404       1.12   mycroft 	return (0);
   1405       1.12   mycroft 
   1406       1.12   mycroft bad:
   1407       1.12   mycroft 	*vpp = NULL;
   1408       1.10       cgd 	return (error);
   1409       1.10       cgd }
   1410      1.116  dholland 
   1411      1.116  dholland /*
   1412      1.116  dholland  * namei_simple - simple forms of namei.
   1413      1.116  dholland  *
   1414      1.116  dholland  * These are wrappers to allow the simple case callers of namei to be
   1415      1.116  dholland  * left alone while everything else changes under them.
   1416      1.116  dholland  */
   1417      1.116  dholland 
   1418      1.116  dholland /* Flags */
   1419      1.116  dholland struct namei_simple_flags_type {
   1420      1.116  dholland 	int dummy;
   1421      1.116  dholland };
   1422      1.116  dholland static const struct namei_simple_flags_type ns_nn, ns_nt, ns_fn, ns_ft;
   1423      1.116  dholland const namei_simple_flags_t NSM_NOFOLLOW_NOEMULROOT = &ns_nn;
   1424      1.116  dholland const namei_simple_flags_t NSM_NOFOLLOW_TRYEMULROOT = &ns_nt;
   1425      1.116  dholland const namei_simple_flags_t NSM_FOLLOW_NOEMULROOT = &ns_fn;
   1426      1.116  dholland const namei_simple_flags_t NSM_FOLLOW_TRYEMULROOT = &ns_ft;
   1427      1.116  dholland 
   1428      1.116  dholland static
   1429      1.116  dholland int
   1430      1.116  dholland namei_simple_convert_flags(namei_simple_flags_t sflags)
   1431      1.116  dholland {
   1432      1.116  dholland 	if (sflags == NSM_NOFOLLOW_NOEMULROOT)
   1433      1.116  dholland 		return NOFOLLOW | 0;
   1434      1.116  dholland 	if (sflags == NSM_NOFOLLOW_TRYEMULROOT)
   1435      1.116  dholland 		return NOFOLLOW | TRYEMULROOT;
   1436      1.116  dholland 	if (sflags == NSM_FOLLOW_NOEMULROOT)
   1437      1.116  dholland 		return FOLLOW | 0;
   1438      1.116  dholland 	if (sflags == NSM_FOLLOW_TRYEMULROOT)
   1439      1.116  dholland 		return FOLLOW | TRYEMULROOT;
   1440      1.116  dholland 	panic("namei_simple_convert_flags: bogus sflags\n");
   1441      1.116  dholland 	return 0;
   1442      1.116  dholland }
   1443      1.116  dholland 
   1444      1.116  dholland int
   1445      1.116  dholland namei_simple_kernel(const char *path, namei_simple_flags_t sflags,
   1446      1.116  dholland 			struct vnode **vp_ret)
   1447      1.116  dholland {
   1448      1.116  dholland 	struct nameidata nd;
   1449      1.116  dholland 	int err;
   1450      1.116  dholland 
   1451      1.116  dholland 	NDINIT(&nd,
   1452      1.116  dholland 		LOOKUP,
   1453      1.116  dholland 		namei_simple_convert_flags(sflags),
   1454      1.116  dholland 		UIO_SYSSPACE,
   1455      1.116  dholland 		path);
   1456      1.116  dholland 	err = namei(&nd);
   1457      1.116  dholland 	if (err != 0) {
   1458      1.116  dholland 		return err;
   1459      1.116  dholland 	}
   1460      1.116  dholland 	*vp_ret = nd.ni_vp;
   1461      1.116  dholland 	return 0;
   1462      1.116  dholland }
   1463      1.116  dholland 
   1464      1.116  dholland int
   1465      1.116  dholland namei_simple_user(const char *path, namei_simple_flags_t sflags,
   1466      1.116  dholland 			struct vnode **vp_ret)
   1467      1.116  dholland {
   1468      1.116  dholland 	struct nameidata nd;
   1469      1.116  dholland 	int err;
   1470      1.116  dholland 
   1471      1.116  dholland 	NDINIT(&nd,
   1472      1.116  dholland 		LOOKUP,
   1473      1.116  dholland 		namei_simple_convert_flags(sflags),
   1474      1.116  dholland 		UIO_USERSPACE,
   1475      1.116  dholland 		path);
   1476      1.116  dholland 	err = namei(&nd);
   1477      1.116  dholland 	if (err != 0) {
   1478      1.116  dholland 		return err;
   1479      1.116  dholland 	}
   1480      1.116  dholland 	*vp_ret = nd.ni_vp;
   1481      1.116  dholland 	return 0;
   1482      1.116  dholland }
   1483