xref: /386bsd/usr/src/kernel/kern/fs/lookup.c (revision dc8b130e)
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
namei(struct nameidata * ndp,struct proc * p)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
nameiexec(struct nameidata * ndp,struct proc * p)211 nameiexec(struct nameidata *ndp, struct proc *p) {
212 	int len;
213 
214 	/* if supplied a process, name the process */
215 	if (p) {
216 		ndp->ni_vp->v_flag |= VTEXT;
217 		len = min(ndp->ni_namelen, MAXCOMLEN);
218 		memcpy(p->p_comm, ndp->ni_ptr, len);
219 		p->p_comm[len] = 0;
220 	}
221 
222 	/* release this namei request */
223 	FREE(ndp->ni_pnbuf, M_NAMEI);
224 	if (ndp->ni_nameiop & LOCKLEAF)
225 		vput(ndp->ni_vp);
226 }
227 
228 /*
229  * Search a pathname.
230  * This is a very central and rather complicated routine.
231  *
232  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
233  * The starting directory is taken from ni_startdir. The pathname is
234  * descended until done, or a symbolic link is encountered. The variable
235  * ni_more is clear if the path is completed; it is set to one if a
236  * symbolic link needing interpretation is encountered.
237  *
238  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
239  * whether the name is to be looked up, created, renamed, or deleted.
240  * When CREATE, RENAME, or DELETE is specified, information usable in
241  * creating, renaming, or deleting a directory entry may be calculated.
242  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
243  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
244  * returned unlocked. Otherwise the parent directory is not returned. If
245  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
246  * the target is returned locked, otherwise it is returned unlocked.
247  * When creating or renaming and LOCKPARENT is specified, the target may not
248  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
249  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked.
250  *
251  * Overall outline of lookup:
252  *
253  * dirloop:
254  *	identify next component of name at ndp->ni_ptr
255  *	handle degenerate case where name is null string
256  *	if .. and crossing mount points and on mounted filesys, find parent
257  *	call VOP_LOOKUP routine for next component name
258  *	    directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
259  *	    component vnode returned in ni_vp (if it exists), locked.
260  *	if result vnode is mounted on and crossing mount points,
261  *	    find mounted on vnode
262  *	if more components of name, do next level at dirloop
263  *	return the answer in ni_vp, locked if LOCKLEAF set
264  *	    if LOCKPARENT set, return locked parent in ni_dvp
265  *	    if WANTPARENT set, return unlocked parent in ni_dvp
266  */
267 int
lookup(struct nameidata * ndp,struct proc * p)268 lookup(struct nameidata *ndp, struct proc *p)
269 {
270 	char *cp;		/* pointer into pathname argument */
271 	struct vnode *dp = 0;	/* the directory we are searching */
272 	struct vnode *tdp;	/* saved dp */
273 	struct mount *mp;	/* mount table entry */
274 	int docache;		/* == 0 do not cache last component */
275 	int flag;		/* LOOKUP, CREATE, RENAME or DELETE */
276 	int wantparent;		/* 1 => wantparent or lockparent flag */
277 	int rdonly;		/* mounted read-only flag bit(s) */
278 	int error = 0;
279 
280 	/*
281 	 * Setup: break out flag bits into variables.
282 	 */
283 	flag = ndp->ni_nameiop & OPMASK;
284 	wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
285 	docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
286 	if (flag == DELETE || (wantparent && flag != CREATE))
287 		docache = 0;
288 	rdonly = MNT_RDONLY;
289 	if (ndp->ni_nameiop & REMOTE)
290 		rdonly |= MNT_EXRDONLY;
291 	ndp->ni_dvp = NULL;
292 	ndp->ni_more = 0;
293 	dp = ndp->ni_startdir;
294 	ndp->ni_startdir = NULLVP;
295 	VOP_LOCK(dp);
296 
297 dirloop:
298 	/*
299 	 * Search a new directory.
300 	 *
301 	 * The ni_hash value is for use by vfs_cache.
302 	 * The last component of the filename is left accessible via
303 	 * ndp->ptr for callers that need the name. Callers needing
304 	 * the name set the SAVENAME flag. When done, they assume
305 	 * responsibility for freeing the pathname buffer.
306 	 */
307 	ndp->ni_hash = 0;
308 	for (cp = ndp->ni_ptr; *cp != 0 && *cp != '/'; cp++)
309 		ndp->ni_hash += (unsigned char)*cp;
310 	ndp->ni_namelen = cp - ndp->ni_ptr;
311 	if (ndp->ni_namelen >= NAME_MAX) {
312 		error = ENAMETOOLONG;
313 		goto bad;
314 	}
315 #ifdef NAMEI_DIAGNOSTIC
316 	{ char c = *cp;
317 	*cp = '\0';
318 	printf("{%s}: ", ndp->ni_ptr);
319 	*cp = c; }
320 #endif
321 	ndp->ni_pathlen -= ndp->ni_namelen;
322 	ndp->ni_next = cp;
323 	ndp->ni_makeentry = 1;
324 	if (*cp == 0 && docache == 0)
325 		ndp->ni_makeentry = 0;
326 	ndp->ni_isdotdot = (ndp->ni_namelen == 2 &&
327 		ndp->ni_ptr[1] == '.' && ndp->ni_ptr[0] == '.');
328 
329 	/*
330 	 * Check for degenerate name (e.g. / or "")
331 	 * which is a way of talking about a directory,
332 	 * e.g. like "/." or ".".
333 	 */
334 	if (ndp->ni_ptr[0] == 0) {
335 		if (flag != LOOKUP || wantparent) {
336 			error = EISDIR;
337 			goto bad;
338 		}
339 		if (dp->v_type != VDIR) {
340 			error = ENOTDIR;
341 			goto bad;
342 		}
343 		if (!(ndp->ni_nameiop & LOCKLEAF))
344 			VOP_UNLOCK(dp);
345 		ndp->ni_vp = dp;
346 		if (ndp->ni_nameiop & SAVESTART)
347 			panic("lookup: SAVESTART");
348 		return (0);
349 	}
350 
351 	/*
352 	 * Handle "..": two special cases.
353 	 * 1. If at root directory (e.g. after chroot)
354 	 *    then ignore it so can't get out.
355 	 * 2. If this vnode is the root of a mounted
356 	 *    filesystem, then replace it with the
357 	 *    vnode which was mounted on so we take the
358 	 *    .. in the other file system.
359 	 */
360 	if (ndp->ni_isdotdot) {
361 		for (;;) {
362 			if (dp == ndp->ni_rootdir || dp == rootdir) {
363 				ndp->ni_dvp = dp;
364 				ndp->ni_vp = dp;
365 				VREF(dp);
366 				goto nextname;
367 			}
368 			if ((dp->v_flag & VROOT) == 0 ||
369 			    (ndp->ni_nameiop & NOCROSSMOUNT))
370 				break;
371 			tdp = dp;
372 			dp = dp->v_mount->mnt_vnodecovered;
373 			vput(tdp);
374 			VREF(dp);
375 			VOP_LOCK(dp);
376 		}
377 	}
378 
379 	/*
380 	 * We now have a segment name to search for, and a directory to search.
381 	 */
382 	if (error = VOP_LOOKUP(dp, ndp, p)) {
383 		if (flag == LOOKUP || flag == DELETE ||
384 		    error != ENOENT || *cp != 0)
385 			goto bad;
386 		/*
387 		 * If creating and at end of pathname, then can consider
388 		 * allowing file to be created.
389 		 */
390 		if (ndp->ni_dvp->v_mount->mnt_flag & rdonly) {
391 			error = EROFS;
392 			goto bad;
393 		}
394 		/*
395 		 * We return with ni_vp NULL to indicate that the entry
396 		 * doesn't currently exist, leaving a pointer to the
397 		 * (possibly locked) directory inode in ndp->ni_dvp.
398 		 */
399 		if (ndp->ni_nameiop & SAVESTART) {
400 			ndp->ni_startdir = ndp->ni_dvp;
401 			VREF(ndp->ni_startdir);
402 		}
403 		return (0);
404 	}
405 
406 	dp = ndp->ni_vp;
407 	/*
408 	 * Check for symbolic link
409 	 */
410 	if ((dp->v_type == VLNK) &&
411 	    ((ndp->ni_nameiop & FOLLOW) || *ndp->ni_next == '/')) {
412 		ndp->ni_more = 1;
413 		return (0);
414 	}
415 
416 	/*
417 	 * Check to see if the vnode has been mounted on;
418 	 * if so find the root of the mounted file system.
419 	 */
420 mntloop:
421 	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
422 	       (ndp->ni_nameiop & NOCROSSMOUNT) == 0) {
423 		while(mp->mnt_flag & MNT_MLOCK) {
424 			mp->mnt_flag |= MNT_MWAIT;
425 			(void) tsleep((caddr_t)mp, PVFS, "lookup", 0);
426 			goto mntloop;
427 		}
428 		if (error = VFS_ROOT(dp->v_mountedhere, &tdp))
429 			goto bad2;
430 		vput(dp);
431 		ndp->ni_vp = dp = tdp;
432 	}
433 
434 nextname:
435 	/*
436 	 * Not a symbolic link.  If more pathname,
437 	 * continue at next component, else return.
438 	 */
439 	if (*ndp->ni_next == '/') {
440 		ndp->ni_ptr = ndp->ni_next;
441 		while (*ndp->ni_ptr == '/') {
442 			ndp->ni_ptr++;
443 			ndp->ni_pathlen--;
444 		}
445 		vrele(ndp->ni_dvp);
446 		goto dirloop;
447 	}
448 	/*
449 	 * Check for read-only file systems.
450 	 */
451 	if (flag == DELETE || flag == RENAME) {
452 		/*
453 		 * Disallow directory write attempts on read-only
454 		 * file systems.
455 		 */
456 		if ((dp->v_mount->mnt_flag & rdonly) ||
457 		    (wantparent && (ndp->ni_dvp->v_mount->mnt_flag & rdonly))) {
458 			error = EROFS;
459 			goto bad2;
460 		}
461 	}
462 	if (ndp->ni_nameiop & SAVESTART) {
463 		ndp->ni_startdir = ndp->ni_dvp;
464 		VREF(ndp->ni_startdir);
465 	}
466 	if (!wantparent)
467 		vrele(ndp->ni_dvp);
468 	if ((ndp->ni_nameiop & LOCKLEAF) == 0)
469 		VOP_UNLOCK(dp);
470 	return (0);
471 
472 bad2:
473 	if ((ndp->ni_nameiop & LOCKPARENT) && *ndp->ni_next == '\0')
474 		VOP_UNLOCK(ndp->ni_dvp);
475 	vrele(ndp->ni_dvp);
476 bad:
477 	vput(dp);
478 	ndp->ni_vp = NULL;
479 	return (error);
480 }
481