xref: /386bsd/usr/src/kernel/kern/fs/lookup.c (revision a2142627)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $Id: lookup.c,v 1.1 94/10/19 17:09:21 bill Exp Locker: bill $
34  */
35 
36 #include "sys/param.h"
37 #include "sys/syslimits.h"
38 #include "sys/time.h"
39 #include "sys/mount.h"
40 #include "sys/errno.h"
41 #include "malloc.h"
42 #include "uio.h"
43 #include "filedesc.h"
44 #include "proc.h"
45 
46 #include "namei.h"
47 #include "vnode.h"
48 
49 #ifdef KTRACE
50 #include "sys/ktrace.h"
51 #endif
52 
53 #include "prototypes.h"
54 
55 /*
56  * Convert a pathname into a pointer to a locked inode.
57  *
58  * The FOLLOW flag is set when symbolic links are to be followed
59  * when they occur at the end of the name translation process.
60  * Symbolic links are always followed for all other pathname
61  * components other than the last.
62  *
63  * The segflg defines whether the name is to be copied from user
64  * space or kernel space.
65  *
66  * Overall outline of namei:
67  *
68  *	copy in name
69  *	get starting directory
70  *	while (!done && !error) {
71  *		call lookup to search path.
72  *		if symbolic link, massage name in buffer and continue
73  *	}
74  */
75 int
76 namei(struct nameidata *ndp, struct proc *p)
77 {
78 	struct filedesc *fdp;	/* pointer to file descriptor state */
79 	char *cp;		/* pointer into pathname argument */
80 	struct vnode *dp;	/* the directory we are searching */
81 	struct iovec aiov;	/* uio for reading symbolic links */
82 	struct uio auio;
83 	int error, linklen;
84 
85 	ndp->ni_cred = p->p_ucred;
86 	fdp = p->p_fd;
87 
88 	/*
89 	 * Get a buffer for the name to be translated, and copy the
90 	 * name into the buffer.
91 	 */
92 	if ((ndp->ni_nameiop & HASBUF) == 0)
93 		MALLOC(ndp->ni_pnbuf, caddr_t, PATH_MAX, M_NAMEI, M_WAITOK);
94 	if (ndp->ni_segflg == UIO_SYSSPACE)
95 		error = copystr(ndp->ni_dirp, ndp->ni_pnbuf,
96 			    PATH_MAX, &ndp->ni_pathlen);
97 	else
98 		error = copyinstr(p, ndp->ni_dirp, ndp->ni_pnbuf,
99 			    PATH_MAX, &ndp->ni_pathlen);
100 	if (error) {
101 		free(ndp->ni_pnbuf, M_NAMEI);
102 		ndp->ni_vp = NULL;
103 		return (error);
104 	}
105 	ndp->ni_loopcnt = 0;
106 #ifdef KTRACE
107 	if (KTRPOINT(p, KTR_NAMEI))
108 		ktrnamei(p->p_tracep, ndp->ni_pnbuf);
109 #endif
110 
111 	/*
112 	 * Get starting point for the translation.
113 	 */
114 	if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
115 		ndp->ni_rootdir = rootdir;
116 	dp = fdp->fd_cdir;
117 	VREF(dp);
118 	for (;;) {
119 		/*
120 		 * Check if root directory should replace current directory.
121 		 * Done at start of translation and after symbolic link.
122 		 */
123 		ndp->ni_ptr = ndp->ni_pnbuf;
124 		if (*ndp->ni_ptr == '/') {
125 			vrele(dp);
126 			while (*ndp->ni_ptr == '/') {
127 				ndp->ni_ptr++;
128 				ndp->ni_pathlen--;
129 			}
130 			dp = ndp->ni_rootdir;
131 			VREF(dp);
132 		}
133 		ndp->ni_startdir = dp;
134 		if (error = lookup(ndp, p)) {
135 			FREE(ndp->ni_pnbuf, M_NAMEI);
136 			return (error);
137 		}
138 		/*
139 		 * Check for symbolic link
140 		 */
141 		if (ndp->ni_more == 0) {
142 
143 			/* name this vnode, as long as it's not . */
144 			if (ndp->ni_vp && !(ndp->ni_isdotdot ||
145 			    (ndp->ni_namelen == 1 && ndp->ni_ptr[0] == '.')))
146 			memcpy(ndp->ni_vp->v_name, ndp->ni_ptr,
147 			    min(ndp->ni_namelen, VN_MAXNAME));
148 
149 			/* special case the root */
150 			if (ndp->ni_vp == rootdir)
151 				memcpy(ndp->ni_vp->v_name, "/", 2);
152 
153 			if ((ndp->ni_nameiop & (SAVENAME | SAVESTART)) == 0)
154 				FREE(ndp->ni_pnbuf, M_NAMEI);
155 			else
156 				ndp->ni_nameiop |= HASBUF;
157 			return (0);
158 		}
159 		if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1)
160 			VOP_UNLOCK(ndp->ni_dvp);
161 		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
162 			error = ELOOP;
163 			break;
164 		}
165 		if (ndp->ni_pathlen > 1)
166 			MALLOC(cp, char *, PATH_MAX, M_NAMEI, M_WAITOK);
167 		else
168 			cp = ndp->ni_pnbuf;
169 		aiov.iov_base = cp;
170 		aiov.iov_len = PATH_MAX;
171 		auio.uio_iov = &aiov;
172 		auio.uio_iovcnt = 1;
173 		auio.uio_offset = 0;
174 		auio.uio_rw = UIO_READ;
175 		auio.uio_segflg = UIO_SYSSPACE;
176 		auio.uio_procp = (struct proc *)0;
177 		auio.uio_resid = PATH_MAX;
178 		if (error = VOP_READLINK(ndp->ni_vp, &auio, p->p_ucred)) {
179 			if (ndp->ni_pathlen > 1)
180 				free(cp, M_NAMEI);
181 			break;
182 		}
183 		linklen = PATH_MAX - auio.uio_resid;
184 		if (linklen + ndp->ni_pathlen >= PATH_MAX) {
185 			if (ndp->ni_pathlen > 1)
186 				free(cp, M_NAMEI);
187 			error = ENAMETOOLONG;
188 			break;
189 		}
190 		if (ndp->ni_pathlen > 1) {
191 			memmove(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
192 			FREE(ndp->ni_pnbuf, M_NAMEI);
193 			ndp->ni_pnbuf = cp;
194 		} else
195 			ndp->ni_pnbuf[linklen] = '\0';
196 		ndp->ni_pathlen += linklen;
197 		vput(ndp->ni_vp);
198 		dp = ndp->ni_dvp;
199 	}
200 	FREE(ndp->ni_pnbuf, M_NAMEI);
201 	vrele(ndp->ni_dvp);
202 	vput(ndp->ni_vp);
203 	ndp->ni_vp = NULL;
204 	return (error);
205 }
206 
207 /*
208  * Label process and release outstanding namei request after execve().
209  */
210 void
211 nameiexec(struct nameidata *ndp, struct proc *p) {
212 	int len;
213 
214 	/* if supplied a process, name the process */
215 	if (p) {
216 		len = min(ndp->ni_namelen, MAXCOMLEN);
217 		memcpy(p->p_comm, ndp->ni_ptr, len);
218 		p->p_comm[len] = 0;
219 	}
220 
221 	/* release this namei request */
222 	FREE(ndp->ni_pnbuf, M_NAMEI);
223 	if (ndp->ni_nameiop & LOCKLEAF)
224 		vput(ndp->ni_vp);
225 }
226 
227 /*
228  * Search a pathname.
229  * This is a very central and rather complicated routine.
230  *
231  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
232  * The starting directory is taken from ni_startdir. The pathname is
233  * descended until done, or a symbolic link is encountered. The variable
234  * ni_more is clear if the path is completed; it is set to one if a
235  * symbolic link needing interpretation is encountered.
236  *
237  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
238  * whether the name is to be looked up, created, renamed, or deleted.
239  * When CREATE, RENAME, or DELETE is specified, information usable in
240  * creating, renaming, or deleting a directory entry may be calculated.
241  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
242  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
243  * returned unlocked. Otherwise the parent directory is not returned. If
244  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
245  * the target is returned locked, otherwise it is returned unlocked.
246  * When creating or renaming and LOCKPARENT is specified, the target may not
247  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
248  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked.
249  *
250  * Overall outline of lookup:
251  *
252  * dirloop:
253  *	identify next component of name at ndp->ni_ptr
254  *	handle degenerate case where name is null string
255  *	if .. and crossing mount points and on mounted filesys, find parent
256  *	call VOP_LOOKUP routine for next component name
257  *	    directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
258  *	    component vnode returned in ni_vp (if it exists), locked.
259  *	if result vnode is mounted on and crossing mount points,
260  *	    find mounted on vnode
261  *	if more components of name, do next level at dirloop
262  *	return the answer in ni_vp, locked if LOCKLEAF set
263  *	    if LOCKPARENT set, return locked parent in ni_dvp
264  *	    if WANTPARENT set, return unlocked parent in ni_dvp
265  */
266 int
267 lookup(struct nameidata *ndp, struct proc *p)
268 {
269 	char *cp;		/* pointer into pathname argument */
270 	struct vnode *dp = 0;	/* the directory we are searching */
271 	struct vnode *tdp;	/* saved dp */
272 	struct mount *mp;	/* mount table entry */
273 	int docache;		/* == 0 do not cache last component */
274 	int flag;		/* LOOKUP, CREATE, RENAME or DELETE */
275 	int wantparent;		/* 1 => wantparent or lockparent flag */
276 	int rdonly;		/* mounted read-only flag bit(s) */
277 	int error = 0;
278 
279 	/*
280 	 * Setup: break out flag bits into variables.
281 	 */
282 	flag = ndp->ni_nameiop & OPMASK;
283 	wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
284 	docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
285 	if (flag == DELETE || (wantparent && flag != CREATE))
286 		docache = 0;
287 	rdonly = MNT_RDONLY;
288 	if (ndp->ni_nameiop & REMOTE)
289 		rdonly |= MNT_EXRDONLY;
290 	ndp->ni_dvp = NULL;
291 	ndp->ni_more = 0;
292 	dp = ndp->ni_startdir;
293 	ndp->ni_startdir = NULLVP;
294 	VOP_LOCK(dp);
295 
296 dirloop:
297 	/*
298 	 * Search a new directory.
299 	 *
300 	 * The ni_hash value is for use by vfs_cache.
301 	 * The last component of the filename is left accessible via
302 	 * ndp->ptr for callers that need the name. Callers needing
303 	 * the name set the SAVENAME flag. When done, they assume
304 	 * responsibility for freeing the pathname buffer.
305 	 */
306 	ndp->ni_hash = 0;
307 	for (cp = ndp->ni_ptr; *cp != 0 && *cp != '/'; cp++)
308 		ndp->ni_hash += (unsigned char)*cp;
309 	ndp->ni_namelen = cp - ndp->ni_ptr;
310 	if (ndp->ni_namelen >= NAME_MAX) {
311 		error = ENAMETOOLONG;
312 		goto bad;
313 	}
314 #ifdef NAMEI_DIAGNOSTIC
315 	{ char c = *cp;
316 	*cp = '\0';
317 	printf("{%s}: ", ndp->ni_ptr);
318 	*cp = c; }
319 #endif
320 	ndp->ni_pathlen -= ndp->ni_namelen;
321 	ndp->ni_next = cp;
322 	ndp->ni_makeentry = 1;
323 	if (*cp == 0 && docache == 0)
324 		ndp->ni_makeentry = 0;
325 	ndp->ni_isdotdot = (ndp->ni_namelen == 2 &&
326 		ndp->ni_ptr[1] == '.' && ndp->ni_ptr[0] == '.');
327 
328 	/*
329 	 * Check for degenerate name (e.g. / or "")
330 	 * which is a way of talking about a directory,
331 	 * e.g. like "/." or ".".
332 	 */
333 	if (ndp->ni_ptr[0] == 0) {
334 		if (flag != LOOKUP || wantparent) {
335 			error = EISDIR;
336 			goto bad;
337 		}
338 		if (dp->v_type != VDIR) {
339 			error = ENOTDIR;
340 			goto bad;
341 		}
342 		if (!(ndp->ni_nameiop & LOCKLEAF))
343 			VOP_UNLOCK(dp);
344 		ndp->ni_vp = dp;
345 		if (ndp->ni_nameiop & SAVESTART)
346 			panic("lookup: SAVESTART");
347 		return (0);
348 	}
349 
350 	/*
351 	 * Handle "..": two special cases.
352 	 * 1. If at root directory (e.g. after chroot)
353 	 *    then ignore it so can't get out.
354 	 * 2. If this vnode is the root of a mounted
355 	 *    filesystem, then replace it with the
356 	 *    vnode which was mounted on so we take the
357 	 *    .. in the other file system.
358 	 */
359 	if (ndp->ni_isdotdot) {
360 		for (;;) {
361 			if (dp == ndp->ni_rootdir || dp == rootdir) {
362 				ndp->ni_dvp = dp;
363 				ndp->ni_vp = dp;
364 				VREF(dp);
365 				goto nextname;
366 			}
367 			if ((dp->v_flag & VROOT) == 0 ||
368 			    (ndp->ni_nameiop & NOCROSSMOUNT))
369 				break;
370 			tdp = dp;
371 			dp = dp->v_mount->mnt_vnodecovered;
372 			vput(tdp);
373 			VREF(dp);
374 			VOP_LOCK(dp);
375 		}
376 	}
377 
378 	/*
379 	 * We now have a segment name to search for, and a directory to search.
380 	 */
381 	if (error = VOP_LOOKUP(dp, ndp, p)) {
382 		if (flag == LOOKUP || flag == DELETE ||
383 		    error != ENOENT || *cp != 0)
384 			goto bad;
385 		/*
386 		 * If creating and at end of pathname, then can consider
387 		 * allowing file to be created.
388 		 */
389 		if (ndp->ni_dvp->v_mount->mnt_flag & rdonly) {
390 			error = EROFS;
391 			goto bad;
392 		}
393 		/*
394 		 * We return with ni_vp NULL to indicate that the entry
395 		 * doesn't currently exist, leaving a pointer to the
396 		 * (possibly locked) directory inode in ndp->ni_dvp.
397 		 */
398 		if (ndp->ni_nameiop & SAVESTART) {
399 			ndp->ni_startdir = ndp->ni_dvp;
400 			VREF(ndp->ni_startdir);
401 		}
402 		return (0);
403 	}
404 
405 	dp = ndp->ni_vp;
406 	/*
407 	 * Check for symbolic link
408 	 */
409 	if ((dp->v_type == VLNK) &&
410 	    ((ndp->ni_nameiop & FOLLOW) || *ndp->ni_next == '/')) {
411 		ndp->ni_more = 1;
412 		return (0);
413 	}
414 
415 	/*
416 	 * Check to see if the vnode has been mounted on;
417 	 * if so find the root of the mounted file system.
418 	 */
419 mntloop:
420 	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
421 	       (ndp->ni_nameiop & NOCROSSMOUNT) == 0) {
422 		while(mp->mnt_flag & MNT_MLOCK) {
423 			mp->mnt_flag |= MNT_MWAIT;
424 			(void) tsleep((caddr_t)mp, PVFS, "lookup", 0);
425 			goto mntloop;
426 		}
427 		if (error = VFS_ROOT(dp->v_mountedhere, &tdp))
428 			goto bad2;
429 		vput(dp);
430 		ndp->ni_vp = dp = tdp;
431 	}
432 
433 nextname:
434 	/*
435 	 * Not a symbolic link.  If more pathname,
436 	 * continue at next component, else return.
437 	 */
438 	if (*ndp->ni_next == '/') {
439 		ndp->ni_ptr = ndp->ni_next;
440 		while (*ndp->ni_ptr == '/') {
441 			ndp->ni_ptr++;
442 			ndp->ni_pathlen--;
443 		}
444 		vrele(ndp->ni_dvp);
445 		goto dirloop;
446 	}
447 	/*
448 	 * Check for read-only file systems.
449 	 */
450 	if (flag == DELETE || flag == RENAME) {
451 		/*
452 		 * Disallow directory write attempts on read-only
453 		 * file systems.
454 		 */
455 		if ((dp->v_mount->mnt_flag & rdonly) ||
456 		    (wantparent && (ndp->ni_dvp->v_mount->mnt_flag & rdonly))) {
457 			error = EROFS;
458 			goto bad2;
459 		}
460 	}
461 	if (ndp->ni_nameiop & SAVESTART) {
462 		ndp->ni_startdir = ndp->ni_dvp;
463 		VREF(ndp->ni_startdir);
464 	}
465 	if (!wantparent)
466 		vrele(ndp->ni_dvp);
467 	if ((ndp->ni_nameiop & LOCKLEAF) == 0)
468 		VOP_UNLOCK(dp);
469 	return (0);
470 
471 bad2:
472 	if ((ndp->ni_nameiop & LOCKPARENT) && *ndp->ni_next == '\0')
473 		VOP_UNLOCK(ndp->ni_dvp);
474 	vrele(ndp->ni_dvp);
475 bad:
476 	vput(dp);
477 	ndp->ni_vp = NULL;
478 	return (error);
479 }
480