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