Annotation of src/sys/kern/vfs_lookup.c, Revision 1.135
1.135 ! dholland 1: /* $NetBSD: vfs_lookup.c,v 1.134 2011/04/11 01:35:00 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.135 ! dholland 40: __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.134 2011/04/11 01:35:00 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: /* used by the pieces of namei */
407: struct vnode *namei_startdir; /* The directory namei() starts from. */
408:
409: /* used by the pieces of lookup */
410: int lookup_alldone;
411:
412: int docache; /* == 0 do not cache last component */
413: int rdonly; /* lookup read-only flag bit */
1.117 dholland 414: struct vnode *dp; /* the directory we are searching */
1.118 dholland 415: int slashes;
1.117 dholland 416: };
417:
1.118 dholland 418:
1.117 dholland 419: /*
420: * Initialize the namei working state.
421: */
422: static void
423: namei_init(struct namei_state *state, struct nameidata *ndp)
424: {
425: state->ndp = ndp;
426: state->cnp = &ndp->ni_cnd;
1.129 dholland 427: KASSERT((state->cnp->cn_flags & INRELOOKUP) == 0);
1.117 dholland 428:
1.118 dholland 429: state->namei_startdir = NULL;
430:
431: state->lookup_alldone = 0;
432:
433: state->docache = 0;
434: state->rdonly = 0;
1.117 dholland 435: state->dp = NULL;
1.118 dholland 436: state->slashes = 0;
1.133 dholland 437:
438: #ifdef DIAGNOSTIC
439: if (!state->cnp->cn_cred)
440: panic("namei: bad cred/proc");
441: if (state->cnp->cn_nameiop & (~OPMASK))
442: panic("namei: nameiop contaminated with flags");
443: if (state->cnp->cn_flags & OPMASK)
444: panic("namei: flags contaminated with nameiops");
445: #endif
446:
447: /*
448: * The buffer for name translation shall be the one inside the
449: * pathbuf.
450: */
451: state->ndp->ni_pnbuf = state->ndp->ni_pathbuf->pb_path;
1.117 dholland 452: }
453:
454: /*
455: * Clean up the working namei state, leaving things ready for return
456: * from namei.
457: */
458: static void
459: namei_cleanup(struct namei_state *state)
460: {
461: KASSERT(state->cnp == &state->ndp->ni_cnd);
462:
1.118 dholland 463: //KASSERT(state->namei_startdir == NULL); // not yet
1.117 dholland 464:
465: /* nothing for now */
466: (void)state;
467: }
468:
469: //////////////////////////////
470:
471: /*
1.133 dholland 472: * Get the directory context.
473: * Initializes the rootdir and erootdir state and returns a reference
474: * to the starting dir.
1.117 dholland 475: */
1.133 dholland 476: static struct vnode *
477: namei_getstartdir(struct namei_state *state)
1.117 dholland 478: {
479: struct nameidata *ndp = state->ndp;
480: struct componentname *cnp = state->cnp;
481: struct cwdinfo *cwdi; /* pointer to cwd state */
482: struct lwp *self = curlwp; /* thread doing namei() */
1.133 dholland 483: struct vnode *rootdir, *erootdir, *curdir, *startdir;
1.117 dholland 484:
1.133 dholland 485: cwdi = self->l_proc->p_cwdi;
486: rw_enter(&cwdi->cwdi_lock, RW_READER);
1.21 kleink 487:
1.133 dholland 488: /* root dir */
489: if (cwdi->cwdi_rdir == NULL || (cnp->cn_flags & NOCHROOT)) {
490: rootdir = rootvnode;
491: } else {
492: rootdir = cwdi->cwdi_rdir;
1.10 cgd 493: }
1.123 dholland 494:
1.133 dholland 495: /* emulation root dir, if any */
496: if ((cnp->cn_flags & TRYEMULROOT) == 0) {
497: /* if we don't want it, don't fetch it */
498: erootdir = NULL;
499: } else if (cnp->cn_flags & EMULROOTSET) {
500: /* explicitly set emulroot; "/../" doesn't override this */
501: erootdir = ndp->ni_erootdir;
502: } else if (!strncmp(ndp->ni_pnbuf, "/../", 4)) {
503: /* explicit reference to real rootdir */
504: erootdir = NULL;
505: } else {
506: /* may be null */
507: erootdir = cwdi->cwdi_edir;
508: }
1.21 kleink 509:
1.133 dholland 510: /* current dir */
511: curdir = cwdi->cwdi_cdir;
1.85 dsl 512:
1.133 dholland 513: if (ndp->ni_pnbuf[0] != '/') {
514: startdir = curdir;
515: erootdir = NULL;
516: } else if (cnp->cn_flags & TRYEMULROOT && erootdir != NULL) {
517: startdir = erootdir;
1.23 mycroft 518: } else {
1.133 dholland 519: startdir = rootdir;
520: erootdir = NULL;
1.23 mycroft 521: }
1.133 dholland 522:
523: state->ndp->ni_rootdir = rootdir;
524: state->ndp->ni_erootdir = erootdir;
1.117 dholland 525:
526: /*
1.133 dholland 527: * Get a reference to the start dir so we can safely unlock cwdi.
528: *
529: * XXX: should we hold references to rootdir and erootdir while
530: * we're running? What happens if a multithreaded process chroots
531: * during namei?
1.117 dholland 532: */
1.133 dholland 533: vref(startdir);
534:
535: rw_exit(&cwdi->cwdi_lock);
536: return startdir;
537: }
538:
539: /*
540: * Get the directory context for the nfsd case, in parallel to
541: * getstartdir. Initializes the rootdir and erootdir state and
542: * returns a reference to the passed-instarting dir.
543: */
544: static struct vnode *
545: namei_getstartdir_for_nfsd(struct namei_state *state, struct vnode *startdir)
546: {
547: /* always use the real root, and never set an emulation root */
548: state->ndp->ni_rootdir = rootvnode;
549: state->ndp->ni_erootdir = NULL;
550:
551: vref(startdir);
552: return startdir;
553: }
554:
555:
556: /*
557: * Ktrace the namei operation.
558: */
559: static void
560: namei_ktrace(struct namei_state *state)
561: {
562: struct nameidata *ndp = state->ndp;
563: struct componentname *cnp = state->cnp;
564: struct lwp *self = curlwp; /* thread doing namei() */
565: const char *emul_path;
566:
1.97 ad 567: if (ktrpoint(KTR_NAMEI)) {
1.90 dsl 568: if (ndp->ni_erootdir != NULL) {
1.89 dsl 569: /*
570: * To make any sense, the trace entry need to have the
571: * text of the emulation path prepended.
572: * Usually we can get this from the current process,
573: * but when called from emul_find_interp() it is only
574: * in the exec_package - so we get it passed in ni_next
575: * (this is a hack).
576: */
1.88 dsl 577: if (cnp->cn_flags & EMULROOTSET)
1.89 dsl 578: emul_path = ndp->ni_next;
1.88 dsl 579: else
1.117 dholland 580: emul_path = self->l_proc->p_emul->e_path;
1.97 ad 581: ktrnamei2(emul_path, strlen(emul_path),
1.124 dholland 582: ndp->ni_pnbuf, ndp->ni_pathlen);
1.88 dsl 583: } else
1.124 dholland 584: ktrnamei(ndp->ni_pnbuf, ndp->ni_pathlen);
1.88 dsl 585: }
1.133 dholland 586: }
587:
588: /*
589: * Start up namei. Copy the path, find the root dir and cwd, establish
590: * the starting directory for lookup, and lock it. Also calls ktrace when
591: * appropriate.
592: */
593: static int
1.134 dholland 594: namei_start(struct namei_state *state, struct vnode *forcecwd)
1.133 dholland 595: {
596: struct nameidata *ndp = state->ndp;
597:
598: /* length includes null terminator (was originally from copyinstr) */
599: ndp->ni_pathlen = strlen(ndp->ni_pnbuf) + 1;
600:
601: /*
602: * POSIX.1 requirement: "" is not a valid file name.
603: */
604: if (ndp->ni_pathlen == 1) {
605: ndp->ni_vp = NULL;
606: return ENOENT;
607: }
608:
609: ndp->ni_loopcnt = 0;
610:
611: /* Get starting directory, set up root, and ktrace. */
1.134 dholland 612: if (forcecwd != NULL) {
1.133 dholland 613: state->namei_startdir = namei_getstartdir_for_nfsd(state,
614: forcecwd);
615: /* no ktrace */
616: } else {
617: state->namei_startdir = namei_getstartdir(state);
618: namei_ktrace(state);
619: }
1.97 ad 620:
1.118 dholland 621: vn_lock(state->namei_startdir, LK_EXCLUSIVE | LK_RETRY);
1.117 dholland 622:
623: return 0;
624: }
625:
626: /*
1.133 dholland 627: * Undo namei_start: unlock and release the current lookup directory.
1.117 dholland 628: */
629: static void
630: namei_end(struct namei_state *state)
631: {
1.118 dholland 632: vput(state->namei_startdir);
1.117 dholland 633: }
634:
635: /*
636: * Check for being at a symlink.
637: */
638: static inline int
639: namei_atsymlink(struct namei_state *state)
640: {
641: return (state->cnp->cn_flags & ISSYMLINK) != 0;
642: }
643:
644: /*
645: * Follow a symlink.
646: */
647: static inline int
1.134 dholland 648: namei_follow(struct namei_state *state, int inhibitmagic)
1.117 dholland 649: {
650: struct nameidata *ndp = state->ndp;
651: struct componentname *cnp = state->cnp;
652:
653: struct lwp *self = curlwp; /* thread doing namei() */
654: struct iovec aiov; /* uio for reading symbolic links */
655: struct uio auio;
656: char *cp; /* pointer into pathname argument */
657: size_t linklen;
658: int error;
659:
660: if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
661: return ELOOP;
662: }
663: if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
664: error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred);
665: if (error != 0)
666: return error;
667: }
1.124 dholland 668:
669: /* FUTURE: fix this to not use a second buffer */
670: cp = PNBUF_GET();
1.117 dholland 671: aiov.iov_base = cp;
672: aiov.iov_len = MAXPATHLEN;
673: auio.uio_iov = &aiov;
674: auio.uio_iovcnt = 1;
675: auio.uio_offset = 0;
676: auio.uio_rw = UIO_READ;
677: auio.uio_resid = MAXPATHLEN;
678: UIO_SETUP_SYSSPACE(&auio);
679: error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
680: if (error) {
1.124 dholland 681: PNBUF_PUT(cp);
1.117 dholland 682: return error;
683: }
684: linklen = MAXPATHLEN - auio.uio_resid;
685: if (linklen == 0) {
1.124 dholland 686: PNBUF_PUT(cp);
687: return ENOENT;
1.117 dholland 688: }
689:
690: /*
691: * Do symlink substitution, if appropriate, and
692: * check length for potential overflow.
1.134 dholland 693: *
694: * Inhibit symlink substitution for nfsd.
695: * XXX: This is how it was before; is that a bug or a feature?
1.117 dholland 696: */
1.134 dholland 697: if ((!inhibitmagic && vfs_magiclinks &&
1.117 dholland 698: symlink_magic(self->l_proc, cp, &linklen)) ||
699: (linklen + ndp->ni_pathlen >= MAXPATHLEN)) {
1.124 dholland 700: PNBUF_PUT(cp);
701: return ENAMETOOLONG;
1.117 dholland 702: }
703: if (ndp->ni_pathlen > 1) {
1.124 dholland 704: /* includes a null-terminator */
1.117 dholland 705: memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
1.124 dholland 706: } else {
707: cp[linklen] = '\0';
708: }
1.117 dholland 709: ndp->ni_pathlen += linklen;
1.124 dholland 710: memcpy(ndp->ni_pnbuf, cp, ndp->ni_pathlen);
711: PNBUF_PUT(cp);
1.117 dholland 712: vput(ndp->ni_vp);
1.118 dholland 713: state->namei_startdir = ndp->ni_dvp;
1.117 dholland 714:
715: /*
716: * Check if root directory should replace current directory.
717: */
1.124 dholland 718: if (ndp->ni_pnbuf[0] == '/') {
1.118 dholland 719: vput(state->namei_startdir);
1.117 dholland 720: /* Keep absolute symbolic links inside emulation root */
1.118 dholland 721: state->namei_startdir = ndp->ni_erootdir;
1.124 dholland 722: if (state->namei_startdir == NULL ||
723: (ndp->ni_pnbuf[1] == '.'
724: && ndp->ni_pnbuf[2] == '.'
725: && ndp->ni_pnbuf[3] == '/')) {
1.117 dholland 726: ndp->ni_erootdir = NULL;
1.118 dholland 727: state->namei_startdir = ndp->ni_rootdir;
1.117 dholland 728: }
1.121 pooka 729: vref(state->namei_startdir);
1.118 dholland 730: vn_lock(state->namei_startdir, LK_EXCLUSIVE | LK_RETRY);
1.117 dholland 731: }
732:
733: return 0;
734: }
735:
736: //////////////////////////////
737:
1.39 lukem 738: /*
1.10 cgd 739: * Search a pathname.
740: * This is a very central and rather complicated routine.
741: *
742: * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
1.128 dholland 743: * The starting directory is passed in. The pathname is descended
744: * until done, or a symbolic link is encountered. The variable ni_more
745: * is clear if the path is completed; it is set to one if a symbolic
746: * link needing interpretation is encountered.
1.10 cgd 747: *
748: * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
749: * whether the name is to be looked up, created, renamed, or deleted.
750: * When CREATE, RENAME, or DELETE is specified, information usable in
751: * creating, renaming, or deleting a directory entry may be calculated.
752: * If flag has LOCKPARENT or'ed into it, the parent directory is returned
1.79 pooka 753: * locked. Otherwise the parent directory is not returned. If the target
754: * of the pathname exists and LOCKLEAF is or'ed into the flag the target
755: * is returned locked, otherwise it is returned unlocked. When creating
756: * or renaming and LOCKPARENT is specified, the target may not be ".".
757: * When deleting and LOCKPARENT is specified, the target may be ".".
1.56 perry 758: *
1.10 cgd 759: * Overall outline of lookup:
760: *
761: * dirloop:
762: * identify next component of name at ndp->ni_ptr
763: * handle degenerate case where name is null string
764: * if .. and crossing mount points and on mounted filesys, find parent
765: * call VOP_LOOKUP routine for next component name
1.79 pooka 766: * directory vnode returned in ni_dvp, locked.
1.10 cgd 767: * component vnode returned in ni_vp (if it exists), locked.
768: * if result vnode is mounted on and crossing mount points,
769: * find mounted on vnode
770: * if more components of name, do next level at dirloop
771: * return the answer in ni_vp, locked if LOCKLEAF set
772: * if LOCKPARENT set, return locked parent in ni_dvp
773: */
1.118 dholland 774:
775: /*
776: * Begin lookup().
777: */
778: static int
1.128 dholland 779: lookup_start(struct namei_state *state, struct vnode *startdir)
1.10 cgd 780: {
1.33 augustss 781: const char *cp; /* pointer into pathname argument */
1.118 dholland 782:
783: struct componentname *cnp = state->cnp;
784: struct nameidata *ndp = state->ndp;
785:
786: KASSERT(cnp == &ndp->ni_cnd);
787:
788: state->lookup_alldone = 0;
789: state->dp = NULL;
1.10 cgd 790:
791: /*
792: * Setup: break out flag bits into variables.
793: */
1.118 dholland 794: state->docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
1.78 pooka 795: if (cnp->cn_nameiop == DELETE)
1.118 dholland 796: state->docache = 0;
797: state->rdonly = cnp->cn_flags & RDONLY;
1.10 cgd 798: ndp->ni_dvp = NULL;
1.12 mycroft 799: cnp->cn_flags &= ~ISSYMLINK;
1.128 dholland 800: state->dp = startdir;
1.10 cgd 801:
1.23 mycroft 802: /*
803: * If we have a leading string of slashes, remove them, and just make
804: * sure the current node is a directory.
805: */
806: cp = cnp->cn_nameptr;
807: if (*cp == '/') {
808: do {
809: cp++;
810: } while (*cp == '/');
811: ndp->ni_pathlen -= cp - cnp->cn_nameptr;
812: cnp->cn_nameptr = cp;
813:
1.118 dholland 814: if (state->dp->v_type != VDIR) {
815: vput(state->dp);
816: return ENOTDIR;
1.23 mycroft 817: }
818:
819: /*
820: * If we've exhausted the path name, then just return the
1.87 dsl 821: * current node.
1.23 mycroft 822: */
823: if (cnp->cn_nameptr[0] == '\0') {
1.118 dholland 824: ndp->ni_vp = state->dp;
1.23 mycroft 825: cnp->cn_flags |= ISLASTCN;
1.118 dholland 826:
827: /* bleh */
828: state->lookup_alldone = 1;
829: return 0;
1.23 mycroft 830: }
831: }
832:
1.118 dholland 833: return 0;
834: }
835:
836: static int
837: lookup_parsepath(struct namei_state *state)
838: {
839: const char *cp; /* pointer into pathname argument */
840:
841: struct componentname *cnp = state->cnp;
842: struct nameidata *ndp = state->ndp;
843:
844: KASSERT(cnp == &ndp->ni_cnd);
845:
1.10 cgd 846: /*
847: * Search a new directory.
848: *
1.12 mycroft 849: * The cn_hash value is for use by vfs_cache.
1.10 cgd 850: * The last component of the filename is left accessible via
1.12 mycroft 851: * cnp->cn_nameptr for callers that need the name. Callers needing
1.10 cgd 852: * the name set the SAVENAME flag. When done, they assume
853: * responsibility for freeing the pathname buffer.
1.127 yamt 854: *
855: * At this point, our only vnode state is that "dp" is held and locked.
1.10 cgd 856: */
1.12 mycroft 857: cnp->cn_consume = 0;
1.39 lukem 858: cp = NULL;
859: cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp);
1.12 mycroft 860: cnp->cn_namelen = cp - cnp->cn_nameptr;
861: if (cnp->cn_namelen > NAME_MAX) {
1.127 yamt 862: vput(state->dp);
863: ndp->ni_dvp = NULL;
1.118 dholland 864: return ENAMETOOLONG;
1.10 cgd 865: }
866: #ifdef NAMEI_DIAGNOSTIC
867: { char c = *cp;
1.41 soren 868: *(char *)cp = '\0';
1.19 christos 869: printf("{%s}: ", cnp->cn_nameptr);
1.41 soren 870: *(char *)cp = c; }
1.52 yamt 871: #endif /* NAMEI_DIAGNOSTIC */
1.12 mycroft 872: ndp->ni_pathlen -= cnp->cn_namelen;
1.10 cgd 873: ndp->ni_next = cp;
1.23 mycroft 874: /*
875: * If this component is followed by a slash, then move the pointer to
876: * the next component forward, and remember that this component must be
877: * a directory.
878: */
879: if (*cp == '/') {
880: do {
881: cp++;
882: } while (*cp == '/');
1.118 dholland 883: state->slashes = cp - ndp->ni_next;
884: ndp->ni_pathlen -= state->slashes;
1.23 mycroft 885: ndp->ni_next = cp;
886: cnp->cn_flags |= REQUIREDIR;
887: } else {
1.118 dholland 888: state->slashes = 0;
1.23 mycroft 889: cnp->cn_flags &= ~REQUIREDIR;
890: }
891: /*
892: * We do special processing on the last component, whether or not it's
893: * a directory. Cache all intervening lookups, but not the final one.
894: */
895: if (*cp == '\0') {
1.118 dholland 896: if (state->docache)
1.23 mycroft 897: cnp->cn_flags |= MAKEENTRY;
898: else
899: cnp->cn_flags &= ~MAKEENTRY;
900: cnp->cn_flags |= ISLASTCN;
901: } else {
902: cnp->cn_flags |= MAKEENTRY;
903: cnp->cn_flags &= ~ISLASTCN;
904: }
1.12 mycroft 905: if (cnp->cn_namelen == 2 &&
906: cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
907: cnp->cn_flags |= ISDOTDOT;
908: else
909: cnp->cn_flags &= ~ISDOTDOT;
1.10 cgd 910:
1.118 dholland 911: return 0;
912: }
913:
914: static int
915: lookup_once(struct namei_state *state)
916: {
917: struct vnode *tdp; /* saved dp */
918: struct mount *mp; /* mount table entry */
919: struct lwp *l = curlwp;
920: int error;
921:
922: struct componentname *cnp = state->cnp;
923: struct nameidata *ndp = state->ndp;
924:
925: KASSERT(cnp == &ndp->ni_cnd);
926:
1.10 cgd 927: /*
928: * Handle "..": two special cases.
929: * 1. If at root directory (e.g. after chroot)
1.12 mycroft 930: * or at absolute root directory
1.10 cgd 931: * then ignore it so can't get out.
1.85 dsl 932: * 1a. If at the root of the emulation filesystem go to the real
933: * root. So "/../<path>" is always absolute.
934: * 1b. If we have somehow gotten out of a jail, warn
1.40 wrstuden 935: * and also ignore it so we can't get farther out.
1.10 cgd 936: * 2. If this vnode is the root of a mounted
937: * filesystem, then replace it with the
938: * vnode which was mounted on so we take the
939: * .. in the other file system.
940: */
1.12 mycroft 941: if (cnp->cn_flags & ISDOTDOT) {
1.64 christos 942: struct proc *p = l->l_proc;
943:
1.10 cgd 944: for (;;) {
1.118 dholland 945: if (state->dp == ndp->ni_rootdir || state->dp == rootvnode) {
946: ndp->ni_dvp = state->dp;
947: ndp->ni_vp = state->dp;
1.121 pooka 948: vref(state->dp);
1.118 dholland 949: return 0;
1.40 wrstuden 950: }
951: if (ndp->ni_rootdir != rootvnode) {
952: int retval;
1.73 chs 953:
1.122 hannken 954: VOP_UNLOCK(state->dp);
1.118 dholland 955: retval = vn_isunder(state->dp, ndp->ni_rootdir, l);
956: vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
1.40 wrstuden 957: if (!retval) {
958: /* Oops! We got out of jail! */
959: log(LOG_WARNING,
960: "chrooted pid %d uid %d (%s) "
961: "detected outside of its chroot\n",
1.71 ad 962: p->p_pid, kauth_cred_geteuid(l->l_cred),
1.64 christos 963: p->p_comm);
1.40 wrstuden 964: /* Put us at the jail root. */
1.118 dholland 965: vput(state->dp);
966: state->dp = ndp->ni_rootdir;
967: ndp->ni_dvp = state->dp;
968: ndp->ni_vp = state->dp;
1.121 pooka 969: vref(state->dp);
970: vref(state->dp);
1.118 dholland 971: vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
972: return 0;
1.40 wrstuden 973: }
1.10 cgd 974: }
1.118 dholland 975: if ((state->dp->v_vflag & VV_ROOT) == 0 ||
1.12 mycroft 976: (cnp->cn_flags & NOCROSSMOUNT))
1.10 cgd 977: break;
1.118 dholland 978: tdp = state->dp;
979: state->dp = state->dp->v_mount->mnt_vnodecovered;
1.10 cgd 980: vput(tdp);
1.121 pooka 981: vref(state->dp);
1.118 dholland 982: vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
1.10 cgd 983: }
984: }
985:
986: /*
987: * We now have a segment name to search for, and a directory to search.
1.73 chs 988: * Again, our only vnode state is that "dp" is held and locked.
1.10 cgd 989: */
1.12 mycroft 990: unionlookup:
1.118 dholland 991: ndp->ni_dvp = state->dp;
1.26 fvdl 992: ndp->ni_vp = NULL;
1.118 dholland 993: error = VOP_LOOKUP(state->dp, &ndp->ni_vp, cnp);
1.73 chs 994: if (error != 0) {
1.10 cgd 995: #ifdef DIAGNOSTIC
996: if (ndp->ni_vp != NULL)
1.43 christos 997: panic("leaf `%s' should be empty", cnp->cn_nameptr);
1.52 yamt 998: #endif /* DIAGNOSTIC */
1.10 cgd 999: #ifdef NAMEI_DIAGNOSTIC
1.19 christos 1000: printf("not found\n");
1.52 yamt 1001: #endif /* NAMEI_DIAGNOSTIC */
1.12 mycroft 1002: if ((error == ENOENT) &&
1.118 dholland 1003: (state->dp->v_vflag & VV_ROOT) &&
1004: (state->dp->v_mount->mnt_flag & MNT_UNION)) {
1005: tdp = state->dp;
1006: state->dp = state->dp->v_mount->mnt_vnodecovered;
1.73 chs 1007: vput(tdp);
1.121 pooka 1008: vref(state->dp);
1.118 dholland 1009: vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
1.12 mycroft 1010: goto unionlookup;
1.10 cgd 1011: }
1.12 mycroft 1012:
1.10 cgd 1013: if (error != EJUSTRETURN)
1.118 dholland 1014: return error;
1.73 chs 1015:
1.10 cgd 1016: /*
1.23 mycroft 1017: * If this was not the last component, or there were trailing
1.51 christos 1018: * slashes, and we are not going to create a directory,
1019: * then the name must exist.
1.23 mycroft 1020: */
1.51 christos 1021: if ((cnp->cn_flags & (REQUIREDIR | CREATEDIR)) == REQUIREDIR) {
1.118 dholland 1022: return ENOENT;
1.23 mycroft 1023: }
1.73 chs 1024:
1.23 mycroft 1025: /*
1.10 cgd 1026: * If creating and at end of pathname, then can consider
1027: * allowing file to be created.
1028: */
1.118 dholland 1029: if (state->rdonly) {
1030: return EROFS;
1.10 cgd 1031: }
1.73 chs 1032:
1.10 cgd 1033: /*
1034: * We return with ni_vp NULL to indicate that the entry
1035: * doesn't currently exist, leaving a pointer to the
1.69 rumble 1036: * (possibly locked) directory vnode in ndp->ni_dvp.
1.10 cgd 1037: */
1.118 dholland 1038: state->lookup_alldone = 1;
1.10 cgd 1039: return (0);
1040: }
1041: #ifdef NAMEI_DIAGNOSTIC
1.19 christos 1042: printf("found\n");
1.52 yamt 1043: #endif /* NAMEI_DIAGNOSTIC */
1.10 cgd 1044:
1.12 mycroft 1045: /*
1.23 mycroft 1046: * Take into account any additional components consumed by the
1047: * underlying filesystem. This will include any trailing slashes after
1048: * the last component consumed.
1.12 mycroft 1049: */
1050: if (cnp->cn_consume > 0) {
1.118 dholland 1051: ndp->ni_pathlen -= cnp->cn_consume - state->slashes;
1052: ndp->ni_next += cnp->cn_consume - state->slashes;
1.12 mycroft 1053: cnp->cn_consume = 0;
1.23 mycroft 1054: if (ndp->ni_next[0] == '\0')
1055: cnp->cn_flags |= ISLASTCN;
1.12 mycroft 1056: }
1057:
1.118 dholland 1058: state->dp = ndp->ni_vp;
1.73 chs 1059:
1060: /*
1.118 dholland 1061: * "state->dp" and "ndp->ni_dvp" are both locked and held,
1.73 chs 1062: * and may be the same vnode.
1063: */
1064:
1.10 cgd 1065: /*
1066: * Check to see if the vnode has been mounted on;
1067: * if so find the root of the mounted file system.
1068: */
1.118 dholland 1069: while (state->dp->v_type == VDIR && (mp = state->dp->v_mountedhere) &&
1.12 mycroft 1070: (cnp->cn_flags & NOCROSSMOUNT) == 0) {
1.108 ad 1071: error = vfs_busy(mp, NULL);
1.107 ad 1072: if (error != 0) {
1.118 dholland 1073: vput(state->dp);
1074: return error;
1.107 ad 1075: }
1.118 dholland 1076: KASSERT(ndp->ni_dvp != state->dp);
1.122 hannken 1077: VOP_UNLOCK(ndp->ni_dvp);
1.118 dholland 1078: vput(state->dp);
1.47 thorpej 1079: error = VFS_ROOT(mp, &tdp);
1.106 ad 1080: vfs_unbusy(mp, false, NULL);
1.32 wrstuden 1081: if (error) {
1.77 chs 1082: vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
1.118 dholland 1083: return error;
1.32 wrstuden 1084: }
1.127 yamt 1085: VOP_UNLOCK(tdp);
1086: ndp->ni_vp = state->dp = tdp;
1087: vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
1088: vn_lock(ndp->ni_vp, LK_EXCLUSIVE | LK_RETRY);
1.14 mycroft 1089: }
1090:
1.118 dholland 1091: return 0;
1092: }
1093:
1094: static int
1.128 dholland 1095: do_lookup(struct namei_state *state, struct vnode *startdir)
1.118 dholland 1096: {
1097: int error = 0;
1098:
1099: struct componentname *cnp = state->cnp;
1100: struct nameidata *ndp = state->ndp;
1101:
1102: KASSERT(cnp == &ndp->ni_cnd);
1103:
1.133 dholland 1104: cnp->cn_nameptr = ndp->ni_pnbuf;
1105:
1.128 dholland 1106: error = lookup_start(state, startdir);
1.118 dholland 1107: if (error) {
1108: goto bad;
1109: }
1110: // XXX: this case should not be necessary given proper handling
1111: // of slashes elsewhere.
1112: if (state->lookup_alldone) {
1113: goto terminal;
1114: }
1115:
1116: dirloop:
1117: error = lookup_parsepath(state);
1118: if (error) {
1119: goto bad;
1120: }
1121:
1122: error = lookup_once(state);
1123: if (error) {
1124: goto bad;
1125: }
1126: // XXX ought to be able to avoid this case too
1127: if (state->lookup_alldone) {
1128: /* this should NOT be "goto terminal;" */
1129: return 0;
1130: }
1131:
1.14 mycroft 1132: /*
1.23 mycroft 1133: * Check for symbolic link. Back up over any slashes that we skipped,
1134: * as we will need them again.
1.14 mycroft 1135: */
1.118 dholland 1136: if ((state->dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
1137: ndp->ni_pathlen += state->slashes;
1138: ndp->ni_next -= state->slashes;
1.14 mycroft 1139: cnp->cn_flags |= ISSYMLINK;
1140: return (0);
1.10 cgd 1141: }
1142:
1.23 mycroft 1143: /*
1144: * Check for directory, if the component was followed by a series of
1145: * slashes.
1146: */
1.118 dholland 1147: if ((state->dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
1.23 mycroft 1148: error = ENOTDIR;
1.118 dholland 1149: KASSERT(state->dp != ndp->ni_dvp);
1150: vput(state->dp);
1.73 chs 1151: goto bad;
1.23 mycroft 1152: }
1153:
1.10 cgd 1154: /*
1.23 mycroft 1155: * Not a symbolic link. If this was not the last component, then
1156: * continue at the next component, else return.
1.10 cgd 1157: */
1.23 mycroft 1158: if (!(cnp->cn_flags & ISLASTCN)) {
1.12 mycroft 1159: cnp->cn_nameptr = ndp->ni_next;
1.118 dholland 1160: if (ndp->ni_dvp == state->dp) {
1.73 chs 1161: vrele(ndp->ni_dvp);
1162: } else {
1163: vput(ndp->ni_dvp);
1164: }
1.10 cgd 1165: goto dirloop;
1166: }
1.23 mycroft 1167:
1168: terminal:
1.118 dholland 1169: if (state->dp == ndp->ni_erootdir) {
1.87 dsl 1170: /*
1171: * We are about to return the emulation root.
1172: * This isn't a good idea because code might repeatedly
1173: * lookup ".." until the file matches that returned
1174: * for "/" and loop forever.
1175: * So convert it to the real root.
1176: */
1.118 dholland 1177: if (ndp->ni_dvp == state->dp)
1178: vrele(state->dp);
1.87 dsl 1179: else
1180: if (ndp->ni_dvp != NULL)
1181: vput(ndp->ni_dvp);
1182: ndp->ni_dvp = NULL;
1.118 dholland 1183: vput(state->dp);
1184: state->dp = ndp->ni_rootdir;
1.121 pooka 1185: vref(state->dp);
1.118 dholland 1186: vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
1187: ndp->ni_vp = state->dp;
1.87 dsl 1188: }
1189:
1190: /*
1191: * If the caller requested the parent node (i.e.
1192: * it's a CREATE, DELETE, or RENAME), and we don't have one
1193: * (because this is the root directory), then we must fail.
1194: */
1195: if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) {
1196: switch (cnp->cn_nameiop) {
1197: case CREATE:
1198: error = EEXIST;
1199: break;
1200: case DELETE:
1201: case RENAME:
1202: error = EBUSY;
1203: break;
1204: default:
1205: KASSERT(0);
1206: }
1.118 dholland 1207: vput(state->dp);
1.87 dsl 1208: goto bad;
1209: }
1.73 chs 1210:
1.10 cgd 1211: /*
1.94 pooka 1212: * Disallow directory write attempts on read-only lookups.
1.96 pooka 1213: * Prefers EEXIST over EROFS for the CREATE case.
1.10 cgd 1214: */
1.118 dholland 1215: if (state->rdonly &&
1.96 pooka 1216: (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
1.26 fvdl 1217: error = EROFS;
1.118 dholland 1218: if (state->dp != ndp->ni_dvp) {
1219: vput(state->dp);
1.73 chs 1220: }
1221: goto bad;
1.10 cgd 1222: }
1.73 chs 1223: if ((cnp->cn_flags & LOCKLEAF) == 0) {
1.122 hannken 1224: VOP_UNLOCK(state->dp);
1.73 chs 1225: }
1.10 cgd 1226: return (0);
1227:
1228: bad:
1229: ndp->ni_vp = NULL;
1.12 mycroft 1230: return (error);
1231: }
1232:
1.131 dholland 1233: //////////////////////////////
1234:
1235: static int
1.134 dholland 1236: do_namei(struct namei_state *state, struct vnode *forcecwd,
1237: int neverfollow, int inhibitmagic)
1.131 dholland 1238: {
1239: int error;
1240:
1241: struct nameidata *ndp = state->ndp;
1242: struct componentname *cnp = state->cnp;
1243: const char *savepath = NULL;
1244:
1245: KASSERT(cnp == &ndp->ni_cnd);
1246:
1247: if (cnp->cn_flags & TRYEMULROOT) {
1248: savepath = pathbuf_stringcopy_get(ndp->ni_pathbuf);
1249: }
1250:
1251: emul_retry:
1252:
1253: if (savepath != NULL) {
1254: /* kinda gross */
1255: strcpy(ndp->ni_pathbuf->pb_path, savepath);
1256: pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath);
1257: savepath = NULL;
1258: }
1259:
1.134 dholland 1260: error = namei_start(state, forcecwd);
1.131 dholland 1261: if (error) {
1262: if (savepath != NULL) {
1263: pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath);
1264: }
1265: return error;
1266: }
1267:
1.133 dholland 1268: /*
1269: * Keep going until we run out of path components.
1270: */
1.131 dholland 1271: for (;;) {
1.133 dholland 1272:
1273: /*
1274: * If the directory we're on is unmounted, bail out.
1275: * XXX: should this also check if it's unlinked?
1276: */
1.131 dholland 1277: if (state->namei_startdir->v_mount == NULL) {
1278: if (savepath != NULL) {
1279: pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath);
1280: }
1281: namei_end(state);
1282: return (ENOENT);
1283: }
1.133 dholland 1284:
1285: /*
1286: * Look up the next path component.
1287: * (currently, this may consume more than one)
1288: */
1.131 dholland 1289: error = do_lookup(state, state->namei_startdir);
1290: if (error != 0) {
1291: /* XXX this should use namei_end() */
1292: if (ndp->ni_dvp) {
1293: vput(ndp->ni_dvp);
1294: }
1295: if (ndp->ni_erootdir != NULL) {
1296: /* Retry the whole thing from the normal root */
1297: cnp->cn_flags &= ~TRYEMULROOT;
1298: goto emul_retry;
1299: }
1300: KASSERT(savepath == NULL);
1301: return (error);
1302: }
1303:
1304: /*
1.133 dholland 1305: * If we've reached a symbolic link, follow it, unless we
1306: * aren't supposed to.
1.131 dholland 1307: */
1308: if (namei_atsymlink(state)) {
1.134 dholland 1309: if (neverfollow) {
1310: error = EINVAL;
1311: } else {
1312: error = namei_follow(state, inhibitmagic);
1313: }
1.131 dholland 1314: if (error) {
1315: KASSERT(ndp->ni_dvp != ndp->ni_vp);
1316: vput(ndp->ni_dvp);
1317: vput(ndp->ni_vp);
1318: ndp->ni_vp = NULL;
1319: if (savepath != NULL) {
1320: pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath);
1321: }
1322: return error;
1323: }
1324: }
1325: else {
1326: break;
1327: }
1328: }
1329:
1330: /*
1.133 dholland 1331: * Done.
1.131 dholland 1332: */
1333:
1.133 dholland 1334: /*
1335: * If LOCKPARENT is not set, the parent directory isn't returned.
1336: */
1337: if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != NULL) {
1.131 dholland 1338: if (ndp->ni_dvp == ndp->ni_vp) {
1339: vrele(ndp->ni_dvp);
1340: } else {
1341: vput(ndp->ni_dvp);
1342: }
1.133 dholland 1343: ndp->ni_dvp = NULL;
1.131 dholland 1344: }
1345:
1346: if (savepath != NULL) {
1347: pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath);
1348: }
1349:
1350: return 0;
1351: }
1352:
1353: int
1354: namei(struct nameidata *ndp)
1355: {
1356: struct namei_state state;
1357: int error;
1358:
1359: namei_init(&state, ndp);
1.134 dholland 1360: error = do_namei(&state, NULL, 0/*!neverfollow*/, 0/*!inhibitmagic*/);
1.131 dholland 1361: namei_cleanup(&state);
1362:
1363: return error;
1364: }
1365:
1366: ////////////////////////////////////////////////////////////
1367:
1.12 mycroft 1368: /*
1.119 dholland 1369: * Externally visible interfaces used by nfsd (bletch, yuk, XXX)
1370: *
1371: * The "index" version differs from the "main" version in that it's
1372: * called from a different place in a different context. For now I
1373: * want to be able to shuffle code in from one call site without
1374: * affecting the other.
1.135 ! dholland 1375: *
! 1376: * It turns out that the "main" version was a cut and pasted copy of
! 1377: * namei with a few changes; the "index" version on the other hand
! 1378: * always takes a single component and is an elaborate form of calling
! 1379: * VOP_LOOKUP once.
1.118 dholland 1380: */
1.119 dholland 1381:
1.134 dholland 1382: int
1.135 ! dholland 1383: lookup_for_nfsd(struct nameidata *ndp, struct vnode *forcecwd, int neverfollow)
1.134 dholland 1384: {
1385: struct namei_state state;
1386: int error;
1.120 dholland 1387:
1.134 dholland 1388: namei_init(&state, ndp);
1.135 ! dholland 1389: error = do_namei(&state, forcecwd, neverfollow, 1/*inhibitmagic*/);
1.119 dholland 1390: namei_cleanup(&state);
1391:
1392: return error;
1393: }
1394:
1.118 dholland 1395: int
1.128 dholland 1396: lookup_for_nfsd_index(struct nameidata *ndp, struct vnode *startdir)
1.118 dholland 1397: {
1398: struct namei_state state;
1399: int error;
1400:
1.133 dholland 1401: /*
1.135 ! dholland 1402: * Note: the name sent in here (is not|should not be) allowed
! 1403: * to contain a slash.
1.133 dholland 1404: */
1405:
1406: ndp->ni_pathlen = strlen(ndp->ni_pathbuf->pb_path) + 1;
1407: ndp->ni_pnbuf = NULL;
1408: ndp->ni_cnd.cn_nameptr = NULL;
1409:
1.128 dholland 1410: vref(startdir);
1411:
1.118 dholland 1412: namei_init(&state, ndp);
1.128 dholland 1413: error = do_lookup(&state, startdir);
1.118 dholland 1414: namei_cleanup(&state);
1415:
1416: return error;
1417: }
1418:
1.131 dholland 1419: ////////////////////////////////////////////////////////////
1420:
1.118 dholland 1421: /*
1.12 mycroft 1422: * Reacquire a path name component.
1.73 chs 1423: * dvp is locked on entry and exit.
1424: * *vpp is locked on exit unless it's NULL.
1.12 mycroft 1425: */
1426: int
1.130 dholland 1427: relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, int dummy)
1.12 mycroft 1428: {
1429: int rdonly; /* lookup read-only flag bit */
1430: int error = 0;
1.52 yamt 1431: #ifdef DEBUG
1.81 chs 1432: uint32_t newhash; /* DEBUG: check name hash */
1.41 soren 1433: const char *cp; /* DEBUG: check name ptr/len */
1.52 yamt 1434: #endif /* DEBUG */
1.12 mycroft 1435:
1.130 dholland 1436: (void)dummy;
1437:
1.12 mycroft 1438: /*
1439: * Setup: break out flag bits into variables.
1440: */
1441: rdonly = cnp->cn_flags & RDONLY;
1442: cnp->cn_flags &= ~ISSYMLINK;
1443:
1444: /*
1445: * Search a new directory.
1446: *
1447: * The cn_hash value is for use by vfs_cache.
1448: * The last component of the filename is left accessible via
1449: * cnp->cn_nameptr for callers that need the name. Callers needing
1450: * the name set the SAVENAME flag. When done, they assume
1451: * responsibility for freeing the pathname buffer.
1452: */
1.52 yamt 1453: #ifdef DEBUG
1.39 lukem 1454: cp = NULL;
1455: newhash = namei_hash(cnp->cn_nameptr, &cp);
1.81 chs 1456: if ((uint32_t)newhash != (uint32_t)cnp->cn_hash)
1.12 mycroft 1457: panic("relookup: bad hash");
1458: if (cnp->cn_namelen != cp - cnp->cn_nameptr)
1.58 christos 1459: panic("relookup: bad len");
1.53 yamt 1460: while (*cp == '/')
1461: cp++;
1.12 mycroft 1462: if (*cp != 0)
1463: panic("relookup: not last component");
1.52 yamt 1464: #endif /* DEBUG */
1.12 mycroft 1465:
1466: /*
1467: * Check for degenerate name (e.g. / or "")
1468: * which is a way of talking about a directory,
1469: * e.g. like "/." or ".".
1470: */
1.23 mycroft 1471: if (cnp->cn_nameptr[0] == '\0')
1472: panic("relookup: null name");
1.12 mycroft 1473:
1474: if (cnp->cn_flags & ISDOTDOT)
1.58 christos 1475: panic("relookup: lookup on dot-dot");
1.12 mycroft 1476:
1477: /*
1478: * We now have a segment name to search for, and a directory to search.
1479: */
1.129 dholland 1480: cnp->cn_flags |= INRELOOKUP;
1481: error = VOP_LOOKUP(dvp, vpp, cnp);
1482: cnp->cn_flags &= ~INRELOOKUP;
1483: if ((error) != 0) {
1.12 mycroft 1484: #ifdef DIAGNOSTIC
1485: if (*vpp != NULL)
1.43 christos 1486: panic("leaf `%s' should be empty", cnp->cn_nameptr);
1.12 mycroft 1487: #endif
1488: if (error != EJUSTRETURN)
1489: goto bad;
1490: }
1491:
1492: #ifdef DIAGNOSTIC
1493: /*
1494: * Check for symbolic link
1495: */
1.81 chs 1496: if (*vpp && (*vpp)->v_type == VLNK && (cnp->cn_flags & FOLLOW))
1.58 christos 1497: panic("relookup: symlink found");
1.12 mycroft 1498: #endif
1499:
1500: /*
1.94 pooka 1501: * Check for read-only lookups.
1.12 mycroft 1502: */
1.81 chs 1503: if (rdonly && cnp->cn_nameiop != LOOKUP) {
1.26 fvdl 1504: error = EROFS;
1.81 chs 1505: if (*vpp) {
1506: vput(*vpp);
1507: }
1.73 chs 1508: goto bad;
1.12 mycroft 1509: }
1510: return (0);
1511:
1512: bad:
1513: *vpp = NULL;
1.10 cgd 1514: return (error);
1515: }
1.116 dholland 1516:
1517: /*
1518: * namei_simple - simple forms of namei.
1519: *
1520: * These are wrappers to allow the simple case callers of namei to be
1521: * left alone while everything else changes under them.
1522: */
1523:
1524: /* Flags */
1525: struct namei_simple_flags_type {
1526: int dummy;
1527: };
1528: static const struct namei_simple_flags_type ns_nn, ns_nt, ns_fn, ns_ft;
1529: const namei_simple_flags_t NSM_NOFOLLOW_NOEMULROOT = &ns_nn;
1530: const namei_simple_flags_t NSM_NOFOLLOW_TRYEMULROOT = &ns_nt;
1531: const namei_simple_flags_t NSM_FOLLOW_NOEMULROOT = &ns_fn;
1532: const namei_simple_flags_t NSM_FOLLOW_TRYEMULROOT = &ns_ft;
1533:
1534: static
1535: int
1536: namei_simple_convert_flags(namei_simple_flags_t sflags)
1537: {
1538: if (sflags == NSM_NOFOLLOW_NOEMULROOT)
1539: return NOFOLLOW | 0;
1540: if (sflags == NSM_NOFOLLOW_TRYEMULROOT)
1541: return NOFOLLOW | TRYEMULROOT;
1542: if (sflags == NSM_FOLLOW_NOEMULROOT)
1543: return FOLLOW | 0;
1544: if (sflags == NSM_FOLLOW_TRYEMULROOT)
1545: return FOLLOW | TRYEMULROOT;
1546: panic("namei_simple_convert_flags: bogus sflags\n");
1547: return 0;
1548: }
1549:
1550: int
1551: namei_simple_kernel(const char *path, namei_simple_flags_t sflags,
1552: struct vnode **vp_ret)
1553: {
1554: struct nameidata nd;
1.123 dholland 1555: struct pathbuf *pb;
1.116 dholland 1556: int err;
1557:
1.123 dholland 1558: pb = pathbuf_create(path);
1559: if (pb == NULL) {
1560: return ENOMEM;
1561: }
1562:
1.116 dholland 1563: NDINIT(&nd,
1564: LOOKUP,
1565: namei_simple_convert_flags(sflags),
1.123 dholland 1566: pb);
1.116 dholland 1567: err = namei(&nd);
1568: if (err != 0) {
1.123 dholland 1569: pathbuf_destroy(pb);
1.116 dholland 1570: return err;
1571: }
1572: *vp_ret = nd.ni_vp;
1.123 dholland 1573: pathbuf_destroy(pb);
1.116 dholland 1574: return 0;
1575: }
1576:
1577: int
1578: namei_simple_user(const char *path, namei_simple_flags_t sflags,
1579: struct vnode **vp_ret)
1580: {
1.123 dholland 1581: struct pathbuf *pb;
1.116 dholland 1582: struct nameidata nd;
1583: int err;
1584:
1.123 dholland 1585: err = pathbuf_copyin(path, &pb);
1586: if (err) {
1587: return err;
1588: }
1589:
1.116 dholland 1590: NDINIT(&nd,
1591: LOOKUP,
1592: namei_simple_convert_flags(sflags),
1.123 dholland 1593: pb);
1.116 dholland 1594: err = namei(&nd);
1595: if (err != 0) {
1.123 dholland 1596: pathbuf_destroy(pb);
1.116 dholland 1597: return err;
1598: }
1599: *vp_ret = nd.ni_vp;
1.123 dholland 1600: pathbuf_destroy(pb);
1.116 dholland 1601: return 0;
1602: }
CVSweb <webmaster@jp.NetBSD.org>