xref: /openbsd-src/sys/kern/vfs_lookup.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: vfs_lookup.c,v 1.63 2016/04/29 14:40:36 beck Exp $	*/
2 /*	$NetBSD: vfs_lookup.c,v 1.17 1996/02/09 19:00:59 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  * (c) UNIX System Laboratories, Inc.
8  * All or some portions of this file are derived from material licensed
9  * to the University of California by American Telephone and Telegraph
10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11  * the permission of UNIX System Laboratories, Inc.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	@(#)vfs_lookup.c	8.6 (Berkeley) 11/21/94
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/syslimits.h>
43 #include <sys/time.h>
44 #include <sys/namei.h>
45 #include <sys/vnode.h>
46 #include <sys/lock.h>
47 #include <sys/mount.h>
48 #include <sys/errno.h>
49 #include <sys/pool.h>
50 #include <sys/filedesc.h>
51 #include <sys/proc.h>
52 #include <sys/pledge.h>
53 #include <sys/file.h>
54 #include <sys/fcntl.h>
55 #include <sys/types.h>
56 #include <sys/malloc.h>
57 
58 #ifdef KTRACE
59 #include <sys/ktrace.h>
60 #endif
61 
62 
63 void
64 push_component(struct nameidata *ndp, char *cp, size_t cplen)
65 {
66 	KASSERT(cplen < MAXPATHLEN);
67 	if (ndp->ni_p_size - ndp->ni_p_length <= cplen) {
68 		char *tmp = malloc(ndp->ni_p_size + MAXPATHLEN, M_TEMP, M_WAITOK);
69 		memcpy(tmp, ndp->ni_p_path, ndp->ni_p_length);
70 		ndp->ni_p_next = tmp + (ndp->ni_p_next - ndp->ni_p_path);
71 		ndp->ni_p_prev = tmp + (ndp->ni_p_prev - ndp->ni_p_path);
72 		free(ndp->ni_p_path, M_TEMP, ndp->ni_p_size);
73 		ndp->ni_p_path = tmp;
74 		ndp->ni_p_size += MAXPATHLEN;
75 	}
76 	memcpy(ndp->ni_p_next, cp, cplen);
77 	ndp->ni_p_prev = ndp->ni_p_next;
78 	ndp->ni_p_next += cplen;
79 	ndp->ni_p_length += cplen;
80 	*ndp->ni_p_next = '\0';
81 #ifdef NAMEI_DIAGNOSTIC_PLEDGE
82 	printf("push: ndp->ni_p_path = %s\n", ndp->ni_p_path);
83 #endif
84 }
85 
86 void
87 pop_symlink(struct nameidata *ndp)
88 {
89 	KASSERT(ndp->ni_p_next != ndp->ni_p_prev);
90 	ndp->ni_p_length = ndp->ni_p_prev - ndp->ni_p_path;
91 	ndp->ni_p_next = ndp->ni_p_prev;
92 	*ndp->ni_p_next = '\0';
93 #ifdef NAMEI_DIAGNOSTIC_PLEDGE
94 	printf("pop: ndp->ni_p_path = %s\n", ndp->ni_p_path);
95 #endif
96 }
97 
98 void
99 ndinitat(struct nameidata *ndp, u_long op, u_long flags,
100     enum uio_seg segflg, int dirfd, const char *namep, struct proc *p)
101 {
102 	memset(ndp, 0, sizeof(*ndp));
103 	(ndp)->ni_cnd.cn_nameiop = op;
104 	(ndp)->ni_cnd.cn_flags = flags;
105 	(ndp)->ni_segflg = segflg;
106 	(ndp)->ni_dirfd = dirfd;
107 	(ndp)->ni_dirp = namep;
108 	(ndp)->ni_cnd.cn_proc = p;
109 }
110 
111 /*
112  * Convert a pathname into a pointer to a vnode.
113  *
114  * The FOLLOW flag is set when symbolic links are to be followed
115  * when they occur at the end of the name translation process.
116  * Symbolic links are always followed for all other pathname
117  * components other than the last.
118  *
119  * If the LOCKLEAF flag is set, a locked vnode is returned.
120  *
121  * The segflg defines whether the name is to be copied from user
122  * space or kernel space.
123  *
124  * Overall outline of namei:
125  *
126  *	copy in name
127  *	get starting directory
128  *	while (!done && !error) {
129  *		call lookup to search path.
130  *		if symbolic link, massage name in buffer and continue
131  *	}
132  */
133 int
134 namei(struct nameidata *ndp)
135 {
136 	struct filedesc *fdp;		/* pointer to file descriptor state */
137 	char *cp;			/* pointer into pathname argument */
138 	struct vnode *dp;		/* the directory we are searching */
139 	struct iovec aiov;		/* uio for reading symbolic links */
140 	struct uio auio;
141 	int error, linklen;
142 	struct componentname *cnp = &ndp->ni_cnd;
143 	struct proc *p = cnp->cn_proc;
144 
145 	/*
146 	 * Should be 0, if not someone didn't init ndp with NDINIT,
147 	 * go find and murder the offender messily.
148 	 */
149 	KASSERT (ndp->ni_p_path == NULL && ndp->ni_p_size == 0);
150 
151 	ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
152 #ifdef DIAGNOSTIC
153 	if (!cnp->cn_cred || !cnp->cn_proc)
154 		panic ("namei: bad cred/proc");
155 	if (cnp->cn_nameiop & (~OPMASK))
156 		panic ("namei: nameiop contaminated with flags");
157 	if (cnp->cn_flags & OPMASK)
158 		panic ("namei: flags contaminated with nameiops");
159 #endif
160 	fdp = cnp->cn_proc->p_fd;
161 
162 	/*
163 	 * Get a buffer for the name to be translated, and copy the
164 	 * name into the buffer.
165 	 */
166 	if ((cnp->cn_flags & HASBUF) == 0)
167 		cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
168 	if (ndp->ni_segflg == UIO_SYSSPACE)
169 		error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
170 			    MAXPATHLEN, &ndp->ni_pathlen);
171 	else
172 		error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
173 			    MAXPATHLEN, &ndp->ni_pathlen);
174 
175 	/*
176 	 * Fail on null pathnames
177 	 */
178 	if (error == 0 && ndp->ni_pathlen == 1)
179 		error = ENOENT;
180 
181 	if (error) {
182 fail:
183 		pool_put(&namei_pool, cnp->cn_pnbuf);
184 		ndp->ni_vp = NULL;
185 		return (error);
186 	}
187 
188 #ifdef KTRACE
189 	if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
190 		ktrnamei(cnp->cn_proc, cnp->cn_pnbuf);
191 #endif
192 
193 	/*
194 	 *  Strip trailing slashes, as requested
195 	 */
196 	if (cnp->cn_flags & STRIPSLASHES) {
197 		char *end = cnp->cn_pnbuf + ndp->ni_pathlen - 2;
198 
199 		cp = end;
200 		while (cp >= cnp->cn_pnbuf && (*cp == '/'))
201 			cp--;
202 
203 		/* Still some remaining characters in the buffer */
204 		if (cp >= cnp->cn_pnbuf) {
205 			ndp->ni_pathlen -= (end - cp);
206 			*(cp + 1) = '\0';
207 		}
208 	}
209 
210 	ndp->ni_loopcnt = 0;
211 
212 	/*
213 	 * Get starting point for the translation.
214 	 */
215 	if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
216 		ndp->ni_rootdir = rootvnode;
217 
218 	error = pledge_namei(p, ndp, cnp->cn_pnbuf);
219 	if (error)
220 		goto fail;
221 
222 	/*
223 	 * Decide if we need to call pledge_namei_wlpath after namei lookup, if
224 	 * so give namei a place to store a path for it to look at.
225 	 */
226 	if (!ISSET(p->p_p->ps_flags, PS_COREDUMP) &&
227 	    ISSET(p->p_p->ps_flags, PS_PLEDGE) && p->p_p->ps_pledgepaths) {
228 		ndp->ni_p_path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
229 		ndp->ni_p_next = ndp->ni_p_prev = ndp->ni_p_path;
230 		ndp->ni_p_size = MAXPATHLEN;
231 		ndp->ni_p_length = 0;
232 	} else {
233 		ndp->ni_p_path = NULL;
234 		ndp->ni_p_size = 0;
235 	}
236 
237 	/*
238 	 * Check if starting from root directory or current directory.
239 	 */
240 	if (cnp->cn_pnbuf[0] == '/') {
241 		dp = ndp->ni_rootdir;
242 		vref(dp);
243 		if (ndp->ni_p_path != NULL) {
244 			*ndp->ni_p_path = '/';
245 			ndp->ni_p_next++;
246 			*ndp->ni_p_next = '\0';
247 			ndp->ni_p_length = 1;
248 		}
249 	} else if (ndp->ni_dirfd == AT_FDCWD) {
250 		dp = fdp->fd_cdir;
251 		vref(dp);
252 	} else {
253 		struct file *fp = fd_getfile(fdp, ndp->ni_dirfd);
254 		if (fp == NULL) {
255 			free(ndp->ni_p_path, M_TEMP, ndp->ni_p_size);
256 			pool_put(&namei_pool, cnp->cn_pnbuf);
257 			return (EBADF);
258 		}
259 		dp = (struct vnode *)fp->f_data;
260 		if (fp->f_type != DTYPE_VNODE || dp->v_type != VDIR) {
261 			free(ndp->ni_p_path, M_TEMP, ndp->ni_p_size);
262 			pool_put(&namei_pool, cnp->cn_pnbuf);
263 			return (ENOTDIR);
264 		}
265 		vref(dp);
266 	}
267 	for (;;) {
268 		if (!dp->v_mount) {
269 			/* Give up if the directory is no longer mounted */
270 			free(ndp->ni_p_path, M_TEMP, ndp->ni_p_size);
271 			pool_put(&namei_pool, cnp->cn_pnbuf);
272 			return (ENOENT);
273 		}
274 		cnp->cn_nameptr = cnp->cn_pnbuf;
275 		ndp->ni_startdir = dp;
276 		if ((error = vfs_lookup(ndp)) != 0) {
277 			free(ndp->ni_p_path, M_TEMP, ndp->ni_p_size);
278 			pool_put(&namei_pool, cnp->cn_pnbuf);
279 			return (error);
280 		}
281 		/*
282 		 * If not a symbolic link, return search result.
283 		 */
284 		if ((cnp->cn_flags & ISSYMLINK) == 0) {
285 			error = pledge_namei_wlpath(p, ndp);
286 			if (error) {
287 #ifdef NAMEI_DIAGNOSTIC_PLEDGE
288 				printf("pledge_namei error %d for path %s\n", error, ndp->ni_p_path);
289 #endif
290 				free(ndp->ni_p_path, M_TEMP, ndp->ni_p_size);
291 				pool_put(&namei_pool, cnp->cn_pnbuf);
292 				if (ndp->ni_vp)
293 					vput(ndp->ni_vp);
294 				ndp->ni_vp = NULL;
295 				return(error);
296 			}
297 			free(ndp->ni_p_path, M_TEMP, ndp->ni_p_size);
298 			if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
299 				pool_put(&namei_pool, cnp->cn_pnbuf);
300 			else
301 				cnp->cn_flags |= HASBUF;
302 			return(0);
303 		}
304 		if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
305 			VOP_UNLOCK(ndp->ni_dvp, p);
306 		if (ndp->ni_loopcnt++ >= SYMLOOP_MAX) {
307 			error = ELOOP;
308 			break;
309 		}
310 		if (ndp->ni_pathlen > 1)
311 			cp = pool_get(&namei_pool, PR_WAITOK);
312 		else
313 			cp = cnp->cn_pnbuf;
314 		aiov.iov_base = cp;
315 		aiov.iov_len = MAXPATHLEN;
316 		auio.uio_iov = &aiov;
317 		auio.uio_iovcnt = 1;
318 		auio.uio_offset = 0;
319 		auio.uio_rw = UIO_READ;
320 		auio.uio_segflg = UIO_SYSSPACE;
321 		auio.uio_procp = cnp->cn_proc;
322 		auio.uio_resid = MAXPATHLEN;
323 		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
324 		if (error) {
325 badlink:
326 			if (ndp->ni_pathlen > 1)
327 				pool_put(&namei_pool, cp);
328 			break;
329 		}
330 		linklen = MAXPATHLEN - auio.uio_resid;
331 		if (linklen == 0) {
332 			error = ENOENT;
333 			goto badlink;
334 		}
335 		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
336 			error = ENAMETOOLONG;
337 			goto badlink;
338 		}
339 		if (ndp->ni_pathlen > 1) {
340 			memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
341 			pool_put(&namei_pool, cnp->cn_pnbuf);
342 			cnp->cn_pnbuf = cp;
343 		} else
344 			cnp->cn_pnbuf[linklen] = '\0';
345 		ndp->ni_pathlen += linklen;
346 		vput(ndp->ni_vp);
347 		dp = ndp->ni_dvp;
348 		/*
349 		 * Check if root directory should replace current directory.
350 		 */
351 		if (cnp->cn_pnbuf[0] == '/') {
352 			vrele(dp);
353 			dp = ndp->ni_rootdir;
354 			vref(dp);
355 			if (ndp->ni_p_path != NULL) {
356 				ndp->ni_p_next = ndp->ni_p_prev = ndp->ni_p_path;
357 				*ndp->ni_p_path = '/';
358 				ndp->ni_p_next++;
359 				*ndp->ni_p_next = '\0';
360 				ndp->ni_p_length = 1;
361 			}
362 		}
363 	}
364 	pool_put(&namei_pool, cnp->cn_pnbuf);
365 	free(ndp->ni_p_path, M_TEMP, ndp->ni_p_size);
366 	vrele(ndp->ni_dvp);
367 	vput(ndp->ni_vp);
368 	ndp->ni_vp = NULL;
369 	return (error);
370 }
371 
372 /*
373  * Search a pathname.
374  * This is a very central and rather complicated routine.
375  *
376  * The pathname is pointed to by ni_cnd.cn_nameptr and is of length
377  * ni_pathlen.  The starting directory is taken from ni_startdir. The
378  * pathname is descended until done, or a symbolic link is encountered.
379  * If the path is completed the flag ISLASTCN is set in ni_cnd.cn_flags.
380  * If a symbolic link need interpretation is encountered, the flag ISSYMLINK
381  * is set in ni_cnd.cn_flags.
382  *
383  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
384  * whether the name is to be looked up, created, renamed, or deleted.
385  * When CREATE, RENAME, or DELETE is specified, information usable in
386  * creating, renaming, or deleting a directory entry may be calculated.
387  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
388  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
389  * returned unlocked. Otherwise the parent directory is not returned. If
390  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
391  * the target is returned locked, otherwise it is returned unlocked.
392  * When creating or renaming and LOCKPARENT is specified, the target may not
393  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
394  *
395  * Overall outline of lookup:
396  *
397  * dirloop:
398  *	identify next component of name at ndp->ni_ptr
399  *	handle degenerate case where name is null string
400  *	if .. and crossing mount points and on mounted filesys, find parent
401  *	call VOP_LOOKUP routine for next component name
402  *	    directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
403  *	    component vnode returned in ni_vp (if it exists), locked.
404  *	if result vnode is mounted on and crossing mount points,
405  *	    find mounted on vnode
406  *	if more components of name, do next level at dirloop
407  *	return the answer in ni_vp, locked if LOCKLEAF set
408  *	    if LOCKPARENT set, return locked parent in ni_dvp
409  *	    if WANTPARENT set, return unlocked parent in ni_dvp
410  */
411 int
412 vfs_lookup(struct nameidata *ndp)
413 {
414 	char *cp;			/* pointer into pathname argument */
415 	struct vnode *dp = 0;		/* the directory we are searching */
416 	struct vnode *tdp;		/* saved dp */
417 	struct mount *mp;		/* mount table entry */
418 	int docache;			/* == 0 do not cache last component */
419 	int wantparent;			/* 1 => wantparent or lockparent flag */
420 	int rdonly;			/* lookup read-only flag bit */
421 	int error = 0;
422 	int dpunlocked = 0;		/* dp has already been unlocked */
423 	int slashes;
424 	struct componentname *cnp = &ndp->ni_cnd;
425 	struct proc *p = cnp->cn_proc;
426 	/*
427 	 * Setup: break out flag bits into variables.
428 	 */
429 	wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
430 	docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
431 	if (cnp->cn_nameiop == DELETE ||
432 	    (wantparent && cnp->cn_nameiop != CREATE))
433 		docache = 0;
434 	rdonly = cnp->cn_flags & RDONLY;
435 	ndp->ni_dvp = NULL;
436 	cnp->cn_flags &= ~ISSYMLINK;
437 	dp = ndp->ni_startdir;
438 	ndp->ni_startdir = NULLVP;
439 	vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
440 
441 	/*
442 	 * If we have a leading string of slashes, remove them, and just make
443 	 * sure the current node is a directory.
444 	 */
445 	cp = cnp->cn_nameptr;
446 	if (*cp == '/') {
447 		do {
448 			cp++;
449 		} while (*cp == '/');
450 		ndp->ni_pathlen -= cp - cnp->cn_nameptr;
451 		cnp->cn_nameptr = cp;
452 
453 		if (dp->v_type != VDIR) {
454 			error = ENOTDIR;
455 			goto bad;
456 		}
457 
458 		/*
459 		 * If we've exhausted the path name, then just return the
460 		 * current node.  If the caller requested the parent node (i.e.
461 		 * it's a CREATE, DELETE, or RENAME), and we don't have one
462 		 * (because this is the root directory), then we must fail.
463 		 */
464 		if (cnp->cn_nameptr[0] == '\0') {
465 			if (ndp->ni_dvp == NULL && wantparent) {
466 				error = EISDIR;
467 				goto bad;
468 			}
469 			ndp->ni_vp = dp;
470 			cnp->cn_flags |= ISLASTCN;
471 			goto terminal;
472 		}
473 	}
474 
475 dirloop:
476 	/*
477 	 * Search a new directory.
478 	 *
479 	 * The last component of the filename is left accessible via
480 	 * cnp->cn_nameptr for callers that need the name. Callers needing
481 	 * the name set the SAVENAME flag. When done, they assume
482 	 * responsibility for freeing the pathname buffer.
483 	 */
484 	cnp->cn_consume = 0;
485 
486 	/* XXX: Figure out the length of the last component. */
487 	cp = cnp->cn_nameptr;
488 	while (*cp && (*cp != '/'))
489 		cp++;
490 	cnp->cn_namelen = cp - cnp->cn_nameptr;
491 	if (cnp->cn_namelen > NAME_MAX) {
492 		error = ENAMETOOLONG;
493 		goto bad;
494 	}
495 
496 #ifdef NAMEI_DIAGNOSTIC
497 #ifdef NAMEI_DIAGNOSTIC_PLEDGE
498 	if (p && p->p_p && p->p_p->ps_pledgepaths)
499 #endif
500 	{ char c = *cp;
501 	*cp = '\0';
502 	printf("{%s}: ", cnp->cn_nameptr);
503 	*cp = c; }
504 #endif
505 	if (ndp->ni_p_path != NULL)
506 		push_component(ndp, cnp->cn_nameptr, cnp->cn_namelen);
507 
508 	ndp->ni_pathlen -= cnp->cn_namelen;
509 	ndp->ni_next = cp;
510 	/*
511 	 * If this component is followed by a slash, then move the pointer to
512 	 * the next component forward, and remember that this component must be
513 	 * a directory.
514 	 */
515 	if (*cp == '/') {
516 		do {
517 			cp++;
518 		} while (*cp == '/');
519 		slashes = cp - ndp->ni_next;
520 		ndp->ni_pathlen -= slashes;
521 		ndp->ni_next = cp;
522 		cnp->cn_flags |= REQUIREDIR;
523 	} else {
524 		slashes = 0;
525 		cnp->cn_flags &= ~REQUIREDIR;
526 	}
527 	/*
528 	 * We do special processing on the last component, whether or not it's
529 	 * a directory.  Cache all intervening lookups, but not the final one.
530 	 */
531 	if (*cp == '\0') {
532 		if (docache)
533 			cnp->cn_flags |= MAKEENTRY;
534 		else
535 			cnp->cn_flags &= ~MAKEENTRY;
536 		cnp->cn_flags |= ISLASTCN;
537 	} else {
538 		cnp->cn_flags |= MAKEENTRY;
539 		cnp->cn_flags &= ~ISLASTCN;
540 	}
541 	if (cnp->cn_namelen == 2 &&
542 	    cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
543 		cnp->cn_flags |= ISDOTDOT;
544 	else
545 		cnp->cn_flags &= ~ISDOTDOT;
546 
547 	/*
548 	 * Handle "..": two special cases.
549 	 * 1. If at root directory (e.g. after chroot)
550 	 *    or at absolute root directory
551 	 *    then ignore it so can't get out.
552 	 * 2. If this vnode is the root of a mounted
553 	 *    filesystem, then replace it with the
554 	 *    vnode which was mounted on so we take the
555 	 *    .. in the other file system.
556 	 */
557 	if (cnp->cn_flags & ISDOTDOT) {
558 		for (;;) {
559 			if (dp == ndp->ni_rootdir || dp == rootvnode) {
560 				ndp->ni_dvp = dp;
561 				ndp->ni_vp = dp;
562 				vref(dp);
563 				goto nextname;
564 			}
565 			if ((dp->v_flag & VROOT) == 0 ||
566 			    (cnp->cn_flags & NOCROSSMOUNT))
567 				break;
568 			tdp = dp;
569 			dp = dp->v_mount->mnt_vnodecovered;
570 			vput(tdp);
571 			vref(dp);
572 			vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
573 		}
574 	}
575 
576 	/*
577 	 * We now have a segment name to search for, and a directory to search.
578 	 */
579 	ndp->ni_dvp = dp;
580 	ndp->ni_vp = NULL;
581 	cnp->cn_flags &= ~PDIRUNLOCK;
582 
583 	if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
584 #ifdef DIAGNOSTIC
585 		if (ndp->ni_vp != NULL)
586 			panic("leaf should be empty");
587 #endif
588 #ifdef NAMEI_DIAGNOSTIC
589 #ifdef NAMEI_DIAGNOSTIC_PLEDGE
590 		if (p && p->p_p && p->p_p->ps_pledgepaths)
591 #endif
592 			printf("not found\n");
593 #endif
594 		if (error != EJUSTRETURN)
595 			goto bad;
596 		/*
597 		 * If this was not the last component, or there were trailing
598 		 * slashes, then the name must exist.
599 		 */
600 		if (cnp->cn_flags & REQUIREDIR) {
601 			error = ENOENT;
602 			goto bad;
603 		}
604 		/*
605 		 * If creating and at end of pathname, then can consider
606 		 * allowing file to be created.
607 		 */
608 		if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) {
609 			error = EROFS;
610 			goto bad;
611 		}
612 		/*
613 		 * We return with ni_vp NULL to indicate that the entry
614 		 * doesn't currently exist, leaving a pointer to the
615 		 * (possibly locked) directory inode in ndp->ni_dvp.
616 		 */
617 		if (cnp->cn_flags & SAVESTART) {
618 			ndp->ni_startdir = ndp->ni_dvp;
619 			vref(ndp->ni_startdir);
620 		}
621 		return (0);
622 	}
623 #ifdef NAMEI_DIAGNOSTIC
624 #ifdef NAMEI_DIAGNOSTIC_PLEDGE
625 	if (p && p->p_p && p->p_p->ps_pledgepaths)
626 #endif
627 		printf("found\n");
628 #endif
629 
630 	/*
631 	 * Take into account any additional components consumed by the
632 	 * underlying filesystem.  This will include any trailing slashes after
633 	 * the last component consumed.
634 	 */
635 	if (cnp->cn_consume > 0) {
636 		if (cnp->cn_consume >= slashes) {
637 			cnp->cn_flags &= ~REQUIREDIR;
638 		}
639 
640 		ndp->ni_pathlen -= cnp->cn_consume - slashes;
641 		ndp->ni_next += cnp->cn_consume - slashes;
642 		cnp->cn_consume = 0;
643 		if (ndp->ni_next[0] == '\0')
644 			cnp->cn_flags |= ISLASTCN;
645 	}
646 
647 	dp = ndp->ni_vp;
648 	/*
649 	 * Check to see if the vnode has been mounted on;
650 	 * if so find the root of the mounted file system.
651 	 */
652 	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
653 	    (cnp->cn_flags & NOCROSSMOUNT) == 0) {
654 		if (vfs_busy(mp, VB_READ|VB_WAIT))
655 			continue;
656 		VOP_UNLOCK(dp, p);
657 		error = VFS_ROOT(mp, &tdp);
658 		vfs_unbusy(mp);
659 		if (error) {
660 			dpunlocked = 1;
661 			goto bad2;
662 		}
663 		vrele(dp);
664 		ndp->ni_vp = dp = tdp;
665 	}
666 
667 	/*
668 	 * Check for symbolic link.  Back up over any slashes that we skipped,
669 	 * as we will need them again.
670 	 */
671 	if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
672 		ndp->ni_pathlen += slashes;
673 		ndp->ni_next -= slashes;
674 		cnp->cn_flags |= ISSYMLINK;
675 		if (ndp->ni_p_path != NULL)
676 			pop_symlink(ndp);
677 		return (0);
678 	}
679 
680 	/*
681 	 * Check for directory, if the component was followed by a series of
682 	 * slashes.
683 	 */
684 	if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
685 		error = ENOTDIR;
686 		goto bad2;
687 	}
688 
689 nextname:
690 	/*
691 	 * Not a symbolic link.  If this was not the last component, then
692 	 * continue at the next component, else return.
693 	 */
694 	if (!(cnp->cn_flags & ISLASTCN)) {
695 		cnp->cn_nameptr = ndp->ni_next;
696 		vrele(ndp->ni_dvp);
697 		if (ndp->ni_p_path != NULL)
698 			push_component(ndp, "/", 1);
699 		goto dirloop;
700 	}
701 
702 terminal:
703 	/*
704 	 * Check for read-only file systems.
705 	 */
706 	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
707 		/*
708 		 * Disallow directory write attempts on read-only
709 		 * file systems.
710 		 */
711 		if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
712 		    (wantparent &&
713 		    (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
714 			error = EROFS;
715 			goto bad2;
716 		}
717 	}
718 	if (ndp->ni_dvp != NULL) {
719 		if (cnp->cn_flags & SAVESTART) {
720 			ndp->ni_startdir = ndp->ni_dvp;
721 			vref(ndp->ni_startdir);
722 		}
723 		if (!wantparent)
724 			vrele(ndp->ni_dvp);
725 	}
726 	if ((cnp->cn_flags & LOCKLEAF) == 0)
727 		VOP_UNLOCK(dp, p);
728 	return (0);
729 
730 bad2:
731 	if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) &&
732 	    ((cnp->cn_flags & PDIRUNLOCK) == 0))
733 		VOP_UNLOCK(ndp->ni_dvp, p);
734 	vrele(ndp->ni_dvp);
735 bad:
736 	if (dpunlocked)
737 		vrele(dp);
738 	else
739 		vput(dp);
740 	ndp->ni_vp = NULL;
741 	return (error);
742 }
743 
744 /*
745  * Reacquire a path name component.
746  */
747 int
748 vfs_relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
749 {
750 	struct proc *p = cnp->cn_proc;
751 	struct vnode *dp = 0;		/* the directory we are searching */
752 	int wantparent;			/* 1 => wantparent or lockparent flag */
753 	int rdonly;			/* lookup read-only flag bit */
754 	int error = 0;
755 #ifdef NAMEI_DIAGNOSTIC
756 	char *cp;			/* DEBUG: check name ptr/len */
757 #endif
758 
759 	/*
760 	 * Setup: break out flag bits into variables.
761 	 */
762 	wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
763 	rdonly = cnp->cn_flags & RDONLY;
764 	cnp->cn_flags &= ~ISSYMLINK;
765 	dp = dvp;
766 	vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
767 
768 /* dirloop: */
769 	/*
770 	 * Search a new directory.
771 	 *
772 	 * The last component of the filename is left accessible via
773 	 * cnp->cn_nameptr for callers that need the name. Callers needing
774 	 * the name set the SAVENAME flag. When done, they assume
775 	 * responsibility for freeing the pathname buffer.
776 	 */
777 
778 #ifdef NAMEI_DIAGNOSTIC
779 #ifdef NAMEI_DIAGNOSTIC_PLEDGE
780 	if (p && p->p_p && p->p_p->ps_pledgepaths)
781 #endif
782 	{
783 		/* XXX: Figure out the length of the last component. */
784 		cp = cnp->cn_nameptr;
785 		while (*cp && (*cp != '/')) {
786 			cp++;
787 		}
788 		if (cnp->cn_namelen != cp - cnp->cn_nameptr)
789 			panic("relookup: bad len");
790 		if (*cp != 0)
791 			panic("relookup: not last component");
792 		printf("{%s}: ", cnp->cn_nameptr);
793 	}
794 #endif
795 
796 	/*
797 	 * Check for degenerate name (e.g. / or "")
798 	 * which is a way of talking about a directory,
799 	 * e.g. like "/." or ".".
800 	 */
801 	if (cnp->cn_nameptr[0] == '\0')
802 		panic("relookup: null name");
803 
804 	if (cnp->cn_flags & ISDOTDOT)
805 		panic ("relookup: lookup on dot-dot");
806 
807 	/*
808 	 * We now have a segment name to search for, and a directory to search.
809 	 */
810 	if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
811 #ifdef DIAGNOSTIC
812 		if (*vpp != NULL)
813 			panic("leaf should be empty");
814 #endif
815 		if (error != EJUSTRETURN)
816 			goto bad;
817 		/*
818 		 * If creating and at end of pathname, then can consider
819 		 * allowing file to be created.
820 		 */
821 		if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) {
822 			error = EROFS;
823 			goto bad;
824 		}
825 		/* ASSERT(dvp == ndp->ni_startdir) */
826 		if (cnp->cn_flags & SAVESTART)
827 			vref(dvp);
828 		/*
829 		 * We return with ni_vp NULL to indicate that the entry
830 		 * doesn't currently exist, leaving a pointer to the
831 		 * (possibly locked) directory inode in ndp->ni_dvp.
832 		 */
833 		return (0);
834 	}
835 	dp = *vpp;
836 
837 #ifdef DIAGNOSTIC
838 	/*
839 	 * Check for symbolic link
840 	 */
841 	if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
842 		panic ("relookup: symlink found.");
843 #endif
844 
845 	/*
846 	 * Check for read-only file systems.
847 	 */
848 	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
849 		/*
850 		 * Disallow directory write attempts on read-only
851 		 * file systems.
852 		 */
853 		if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
854 		    (wantparent &&
855 		    (dvp->v_mount->mnt_flag & MNT_RDONLY))) {
856 			error = EROFS;
857 			goto bad2;
858 		}
859 	}
860 	/* ASSERT(dvp == ndp->ni_startdir) */
861 	if (cnp->cn_flags & SAVESTART)
862 		vref(dvp);
863 	if (!wantparent)
864 		vrele(dvp);
865 	if ((cnp->cn_flags & LOCKLEAF) == 0)
866 		VOP_UNLOCK(dp, p);
867 	return (0);
868 
869 bad2:
870 	if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
871 		VOP_UNLOCK(dvp, p);
872 	vrele(dvp);
873 bad:
874 	vput(dp);
875 	*vpp = NULL;
876 	return (error);
877 }
878