[BACK]Return to vfs_lookup.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/vfs_lookup.c, Revision 1.197

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

CVSweb <webmaster@jp.NetBSD.org>