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