[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.72.2.4

1.72.2.4! riz         1: /*     $NetBSD: vfs_lookup.c,v 1.72.2.3 2007/02/17 23:27:47 tron 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.72.2.4! riz        40: __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.72.2.3 2007/02/17 23:27:47 tron Exp $");
1.27      thorpej    41:
                     42: #include "opt_ktrace.h"
1.50      cb         43: #include "opt_systrace.h"
1.67      chs        44: #include "opt_magiclinks.h"
1.10      cgd        45:
                     46: #include <sys/param.h>
1.15      cgd        47: #include <sys/systm.h>
1.61      thorpej    48: #include <sys/kernel.h>
1.10      cgd        49: #include <sys/syslimits.h>
                     50: #include <sys/time.h>
                     51: #include <sys/namei.h>
                     52: #include <sys/vnode.h>
                     53: #include <sys/mount.h>
                     54: #include <sys/errno.h>
1.39      lukem      55: #include <sys/filedesc.h>
                     56: #include <sys/hash.h>
1.10      cgd        57: #include <sys/malloc.h>
                     58: #include <sys/proc.h>
1.40      wrstuden   59: #include <sys/syslog.h>
1.70      elad       60: #include <sys/kauth.h>
1.12      mycroft    61:
1.10      cgd        62: #ifdef KTRACE
                     63: #include <sys/ktrace.h>
                     64: #endif
1.50      cb         65: #ifdef SYSTRACE
                     66: #include <sys/systrace.h>
                     67: #endif
1.16      christos   68:
1.67      chs        69: #ifndef MAGICLINKS
                     70: #define MAGICLINKS 0
                     71: #endif
                     72:
1.72.2.1  tron       73: struct pathname_internal {
                     74:        char *pathbuf;
                     75:        boolean_t needfree;
                     76: };
                     77:
1.67      chs        78: int vfs_magiclinks = MAGICLINKS;
                     79:
1.35      thorpej    80: struct pool pnbuf_pool;                /* pathname buffer pool */
1.37      thorpej    81: struct pool_cache pnbuf_cache; /* pathname buffer cache */
1.44      thorpej    82:
1.10      cgd        83: /*
1.61      thorpej    84:  * Substitute replacement text for 'magic' strings in symlinks.
                     85:  * Returns 0 if successful, and returns non-zero if an error
                     86:  * occurs.  (Currently, the only possible error is running out
                     87:  * of temporary pathname space.)
                     88:  *
                     89:  * Looks for "@<string>" and "@<string>/", where <string> is a
                     90:  * recognized 'magic' string.  Replaces the "@<string>" with the
                     91:  * appropriate replacement text.  (Note that in some cases the
                     92:  * replacement text may have zero length.)
                     93:  *
                     94:  * This would have been table driven, but the variance in
                     95:  * replacement strings (and replacement string lengths) made
                     96:  * that impractical.
                     97:  */
1.63      thorpej    98: #define        VNL(x)                                                  \
                     99:        (sizeof(x) - 1)
                    100:
                    101: #define        VO      '{'
                    102: #define        VC      '}'
                    103:
1.61      thorpej   104: #define        MATCH(str)                                              \
1.63      thorpej   105:        ((termchar == '/' && i + VNL(str) == *len) ||           \
                    106:         (i + VNL(str) < *len &&                                \
                    107:          cp[i + VNL(str)] == termchar)) &&                     \
                    108:        !strncmp((str), &cp[i], VNL(str))
1.61      thorpej   109:
                    110: #define        SUBSTITUTE(m, s, sl)                                    \
1.63      thorpej   111:        if ((newlen + (sl)) > MAXPATHLEN)                       \
                    112:                return (1);                                     \
                    113:        i += VNL(m);                                            \
                    114:        if (termchar != '/')                                    \
                    115:                i++;                                            \
                    116:        memcpy(&tmp[newlen], (s), (sl));                        \
                    117:        newlen += (sl);                                         \
                    118:        change = 1;                                             \
                    119:        termchar = '/';
1.61      thorpej   120:
                    121: static int
1.63      thorpej   122: symlink_magic(struct proc *p, char *cp, int *len)
1.61      thorpej   123: {
1.66      yamt      124:        char *tmp;
1.61      thorpej   125:        int change, i, newlen;
1.63      thorpej   126:        int termchar = '/';
1.61      thorpej   127:
1.66      yamt      128:        tmp = PNBUF_GET();
1.61      thorpej   129:        for (change = i = newlen = 0; i < *len; ) {
1.63      thorpej   130:                if (cp[i] != '@') {
1.61      thorpej   131:                        tmp[newlen++] = cp[i++];
1.63      thorpej   132:                        continue;
                    133:                }
                    134:
                    135:                i++;
                    136:
                    137:                /* Check for @{var} syntax. */
                    138:                if (cp[i] == VO) {
                    139:                        termchar = VC;
1.61      thorpej   140:                        i++;
1.63      thorpej   141:                }
                    142:
                    143:                /*
                    144:                 * The following checks should be ordered according
                    145:                 * to frequency of use.
                    146:                 */
                    147:                if (MATCH("machine_arch")) {
                    148:                        SUBSTITUTE("machine_arch", MACHINE_ARCH,
                    149:                            sizeof(MACHINE_ARCH) - 1);
                    150:                } else if (MATCH("machine")) {
                    151:                        SUBSTITUTE("machine", MACHINE,
                    152:                            sizeof(MACHINE) - 1);
                    153:                } else if (MATCH("hostname")) {
                    154:                        SUBSTITUTE("hostname", hostname,
                    155:                            hostnamelen);
                    156:                } else if (MATCH("osrelease")) {
                    157:                        SUBSTITUTE("osrelease", osrelease,
                    158:                            strlen(osrelease));
                    159:                } else if (MATCH("emul")) {
                    160:                        SUBSTITUTE("emul", p->p_emul->e_name,
                    161:                            strlen(p->p_emul->e_name));
                    162:                } else if (MATCH("kernel_ident")) {
                    163:                        SUBSTITUTE("kernel_ident", kernel_ident,
                    164:                            strlen(kernel_ident));
                    165:                } else if (MATCH("domainname")) {
                    166:                        SUBSTITUTE("domainname", domainname,
                    167:                            domainnamelen);
                    168:                } else if (MATCH("ostype")) {
                    169:                        SUBSTITUTE("ostype", ostype,
                    170:                            strlen(ostype));
1.72      elad      171:                } else if (MATCH("uid")) {
                    172:                        char uidtmp[11]; /* XXX elad */
                    173:
                    174:                        (void)snprintf(uidtmp, sizeof(uidtmp), "%u",
                    175:                            kauth_cred_geteuid(kauth_cred_get()));
                    176:                        SUBSTITUTE("uid", uidtmp, strlen(uidtmp));
1.63      thorpej   177:                } else {
                    178:                        tmp[newlen++] = '@';
                    179:                        if (termchar == VC)
                    180:                                tmp[newlen++] = VO;
1.61      thorpej   181:                }
                    182:        }
                    183:
1.66      yamt      184:        if (change) {
                    185:                memcpy(cp, tmp, newlen);
                    186:                *len = newlen;
                    187:        }
                    188:        PNBUF_PUT(tmp);
1.61      thorpej   189:
                    190:        return (0);
                    191: }
                    192:
1.63      thorpej   193: #undef VNL
                    194: #undef VO
                    195: #undef VC
                    196: #undef MATCH
                    197: #undef SUBSTITUTE
                    198:
1.72.2.1  tron      199: int
                    200: pathname_get(const char *dirp, enum uio_seg segflg, pathname_t *path)
                    201: {
                    202:        int error;
                    203:
                    204:        if (dirp == NULL)
                    205:                return (EFAULT);
                    206:
                    207:        *path = malloc(sizeof(struct pathname_internal), M_TEMP,
                    208:            M_ZERO|M_WAITOK);
                    209:
                    210:        if (segflg == UIO_USERSPACE) {
                    211:                (*path)->pathbuf = PNBUF_GET();
                    212:                error = copyinstr(dirp, (*path)->pathbuf, MAXPATHLEN,
                    213:                    NULL);
                    214:                if (error) {
                    215:                        PNBUF_PUT((*path)->pathbuf);
1.72.2.2  tron      216:                        free(*path, M_TEMP);
                    217:                        *path = NULL;
1.72.2.1  tron      218:                        return (error);
                    219:                }
                    220:                (*path)->needfree = TRUE;
                    221:        } else {
                    222:                (*path)->pathbuf = __UNCONST(dirp);
                    223:                (*path)->needfree = FALSE;
                    224:        }
                    225:
                    226:        return (0);
                    227: }
                    228:
                    229: const char *
                    230: pathname_path(pathname_t path)
                    231: {
                    232:        KASSERT(path != NULL);
                    233:        return (path->pathbuf);
                    234: }
                    235:
                    236: void
                    237: pathname_put(pathname_t path)
                    238: {
                    239:        if (path != NULL) {
                    240:                if (path->pathbuf != NULL && path->needfree)
                    241:                        PNBUF_PUT(path->pathbuf);
                    242:                free(path, M_TEMP);
                    243:        }
                    244: }
                    245:
1.61      thorpej   246: /*
1.69      rumble    247:  * Convert a pathname into a pointer to a locked vnode.
1.10      cgd       248:  *
                    249:  * The FOLLOW flag is set when symbolic links are to be followed
                    250:  * when they occur at the end of the name translation process.
                    251:  * Symbolic links are always followed for all other pathname
                    252:  * components other than the last.
                    253:  *
                    254:  * The segflg defines whether the name is to be copied from user
                    255:  * space or kernel space.
                    256:  *
                    257:  * Overall outline of namei:
                    258:  *
                    259:  *     copy in name
                    260:  *     get starting directory
                    261:  *     while (!done && !error) {
                    262:  *             call lookup to search path.
                    263:  *             if symbolic link, massage name in buffer and continue
                    264:  *     }
                    265:  */
1.12      mycroft   266: int
1.60      thorpej   267: namei(struct nameidata *ndp)
1.10      cgd       268: {
1.30      thorpej   269:        struct cwdinfo *cwdi;           /* pointer to cwd state */
1.33      augustss  270:        char *cp;                       /* pointer into pathname argument */
                    271:        struct vnode *dp;               /* the directory we are searching */
1.10      cgd       272:        struct iovec aiov;              /* uio for reading symbolic links */
                    273:        struct uio auio;
1.23      mycroft   274:        int error, linklen;
1.12      mycroft   275:        struct componentname *cnp = &ndp->ni_cnd;
1.10      cgd       276:
1.12      mycroft   277: #ifdef DIAGNOSTIC
1.64      christos  278:        if (!cnp->cn_cred || !cnp->cn_lwp)
1.58      christos  279:                panic("namei: bad cred/proc");
1.12      mycroft   280:        if (cnp->cn_nameiop & (~OPMASK))
1.58      christos  281:                panic("namei: nameiop contaminated with flags");
1.12      mycroft   282:        if (cnp->cn_flags & OPMASK)
1.58      christos  283:                panic("namei: flags contaminated with nameiops");
1.12      mycroft   284: #endif
1.64      christos  285:        cwdi = cnp->cn_lwp->l_proc->p_cwdi;
1.10      cgd       286:
                    287:        /*
                    288:         * Get a buffer for the name to be translated, and copy the
                    289:         * name into the buffer.
                    290:         */
1.12      mycroft   291:        if ((cnp->cn_flags & HASBUF) == 0)
1.35      thorpej   292:                cnp->cn_pnbuf = PNBUF_GET();
1.10      cgd       293:        if (ndp->ni_segflg == UIO_SYSSPACE)
1.12      mycroft   294:                error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
1.10      cgd       295:                            MAXPATHLEN, &ndp->ni_pathlen);
                    296:        else
1.12      mycroft   297:                error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
1.10      cgd       298:                            MAXPATHLEN, &ndp->ni_pathlen);
1.21      kleink    299:
                    300:        /*
                    301:         * POSIX.1 requirement: "" is not a valid file name.
1.56      perry     302:         */
1.21      kleink    303:        if (!error && ndp->ni_pathlen == 1)
                    304:                error = ENOENT;
                    305:
1.10      cgd       306:        if (error) {
1.35      thorpej   307:                PNBUF_PUT(cnp->cn_pnbuf);
1.10      cgd       308:                ndp->ni_vp = NULL;
                    309:                return (error);
                    310:        }
                    311:        ndp->ni_loopcnt = 0;
1.21      kleink    312:
1.10      cgd       313: #ifdef KTRACE
1.64      christos  314:        if (KTRPOINT(cnp->cn_lwp->l_proc, KTR_NAMEI))
                    315:                ktrnamei(cnp->cn_lwp, cnp->cn_pnbuf);
1.50      cb        316: #endif
                    317: #ifdef SYSTRACE
1.64      christos  318:        if (ISSET(cnp->cn_lwp->l_proc->p_flag, P_SYSTRACE))
1.50      cb        319:                systrace_namei(ndp);
1.10      cgd       320: #endif
                    321:
                    322:        /*
                    323:         * Get starting point for the translation.
                    324:         */
1.30      thorpej   325:        if ((ndp->ni_rootdir = cwdi->cwdi_rdir) == NULL)
1.11      cgd       326:                ndp->ni_rootdir = rootvnode;
1.23      mycroft   327:        /*
                    328:         * Check if starting from root directory or current directory.
                    329:         */
                    330:        if (cnp->cn_pnbuf[0] == '/') {
                    331:                dp = ndp->ni_rootdir;
                    332:                VREF(dp);
                    333:        } else {
1.30      thorpej   334:                dp = cwdi->cwdi_cdir;
1.23      mycroft   335:                VREF(dp);
                    336:        }
1.72.2.3  tron      337:        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.10      cgd       338:        for (;;) {
1.72.2.3  tron      339:                if (!dp->v_mount) {
1.45      erh       340:                        /* Give up if the directory is no longer mounted */
1.72.2.3  tron      341:                        vput(dp);
1.45      erh       342:                        PNBUF_PUT(cnp->cn_pnbuf);
                    343:                        return (ENOENT);
                    344:                }
1.12      mycroft   345:                cnp->cn_nameptr = cnp->cn_pnbuf;
1.10      cgd       346:                ndp->ni_startdir = dp;
1.72.2.3  tron      347:                error = lookup(ndp);
                    348:                if (error != 0) {
                    349:                        if (ndp->ni_dvp) {
                    350:                                vput(ndp->ni_dvp);
                    351:                        }
1.35      thorpej   352:                        PNBUF_PUT(cnp->cn_pnbuf);
1.10      cgd       353:                        return (error);
                    354:                }
1.72.2.3  tron      355:
1.10      cgd       356:                /*
                    357:                 * Check for symbolic link
                    358:                 */
1.12      mycroft   359:                if ((cnp->cn_flags & ISSYMLINK) == 0) {
1.72.2.3  tron      360:                        if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
                    361:                                if (ndp->ni_dvp == ndp->ni_vp) {
                    362:                                        vrele(ndp->ni_dvp);
                    363:                                } else {
                    364:                                        vput(ndp->ni_dvp);
                    365:                                }
                    366:                        }
1.12      mycroft   367:                        if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
1.35      thorpej   368:                                PNBUF_PUT(cnp->cn_pnbuf);
1.10      cgd       369:                        else
1.12      mycroft   370:                                cnp->cn_flags |= HASBUF;
1.10      cgd       371:                        return (0);
                    372:                }
1.72.2.3  tron      373:
1.10      cgd       374:                if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
                    375:                        error = ELOOP;
                    376:                        break;
                    377:                }
1.25      enami     378:                if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
                    379:                        error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred,
1.64      christos  380:                            cnp->cn_lwp);
1.25      enami     381:                        if (error != 0)
                    382:                                break;
                    383:                }
1.10      cgd       384:                if (ndp->ni_pathlen > 1)
1.35      thorpej   385:                        cp = PNBUF_GET();
1.10      cgd       386:                else
1.12      mycroft   387:                        cp = cnp->cn_pnbuf;
1.10      cgd       388:                aiov.iov_base = cp;
                    389:                aiov.iov_len = MAXPATHLEN;
                    390:                auio.uio_iov = &aiov;
                    391:                auio.uio_iovcnt = 1;
                    392:                auio.uio_offset = 0;
                    393:                auio.uio_rw = UIO_READ;
                    394:                auio.uio_resid = MAXPATHLEN;
1.68      yamt      395:                UIO_SETUP_SYSSPACE(&auio);
1.16      christos  396:                error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
                    397:                if (error) {
1.72.2.3  tron      398: badlink:
1.10      cgd       399:                        if (ndp->ni_pathlen > 1)
1.35      thorpej   400:                                PNBUF_PUT(cp);
1.10      cgd       401:                        break;
                    402:                }
                    403:                linklen = MAXPATHLEN - auio.uio_resid;
1.23      mycroft   404:                if (linklen == 0) {
                    405:                        error = ENOENT;
                    406:                        goto badlink;
                    407:                }
1.72.2.3  tron      408:
1.61      thorpej   409:                /*
                    410:                 * Do symlink substitution, if appropriate, and
                    411:                 * check length for potential overflow.
                    412:                 */
1.67      chs       413:                if ((vfs_magiclinks &&
1.64      christos  414:                     symlink_magic(cnp->cn_lwp->l_proc, cp, &linklen)) ||
1.61      thorpej   415:                    (linklen + ndp->ni_pathlen >= MAXPATHLEN)) {
1.10      cgd       416:                        error = ENAMETOOLONG;
1.23      mycroft   417:                        goto badlink;
1.10      cgd       418:                }
                    419:                if (ndp->ni_pathlen > 1) {
1.28      perry     420:                        memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
1.35      thorpej   421:                        PNBUF_PUT(cnp->cn_pnbuf);
1.12      mycroft   422:                        cnp->cn_pnbuf = cp;
1.10      cgd       423:                } else
1.12      mycroft   424:                        cnp->cn_pnbuf[linklen] = '\0';
1.10      cgd       425:                ndp->ni_pathlen += linklen;
                    426:                vput(ndp->ni_vp);
                    427:                dp = ndp->ni_dvp;
1.72.2.3  tron      428:
1.23      mycroft   429:                /*
                    430:                 * Check if root directory should replace current directory.
                    431:                 */
                    432:                if (cnp->cn_pnbuf[0] == '/') {
1.72.2.3  tron      433:                        vput(dp);
1.23      mycroft   434:                        dp = ndp->ni_rootdir;
                    435:                        VREF(dp);
1.72.2.3  tron      436:                        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.23      mycroft   437:                }
1.10      cgd       438:        }
1.72.2.3  tron      439:        KASSERT(ndp->ni_dvp != ndp->ni_vp);
                    440:        vput(ndp->ni_dvp);
1.10      cgd       441:        vput(ndp->ni_vp);
                    442:        ndp->ni_vp = NULL;
1.72.2.3  tron      443:        PNBUF_PUT(cnp->cn_pnbuf);
1.10      cgd       444:        return (error);
                    445: }
                    446:
                    447: /*
1.39      lukem     448:  * Determine the namei hash (for cn_hash) for name.
                    449:  * If *ep != NULL, hash from name to ep-1.
                    450:  * If *ep == NULL, hash from name until the first NUL or '/', and
                    451:  * return the location of this termination character in *ep.
                    452:  *
                    453:  * This function returns an equivalent hash to the MI hash32_strn().
                    454:  * The latter isn't used because in the *ep == NULL case, determining
                    455:  * the length of the string to the first NUL or `/' and then calling
                    456:  * hash32_strn() involves unnecessary double-handling of the data.
                    457:  */
                    458: uint32_t
                    459: namei_hash(const char *name, const char **ep)
                    460: {
                    461:        uint32_t        hash;
                    462:
                    463:        hash = HASH32_STR_INIT;
                    464:        if (*ep != NULL) {
                    465:                for (; name < *ep; name++)
1.59      christos  466:                        hash = hash * 33 + *(const uint8_t *)name;
1.39      lukem     467:        } else {
                    468:                for (; *name != '\0' && *name != '/'; name++)
1.59      christos  469:                        hash = hash * 33 + *(const uint8_t *)name;
1.39      lukem     470:                *ep = name;
                    471:        }
                    472:        return (hash + (hash >> 5));
                    473: }
                    474:
                    475: /*
1.10      cgd       476:  * Search a pathname.
                    477:  * This is a very central and rather complicated routine.
                    478:  *
                    479:  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
                    480:  * The starting directory is taken from ni_startdir. The pathname is
                    481:  * descended until done, or a symbolic link is encountered. The variable
                    482:  * ni_more is clear if the path is completed; it is set to one if a
                    483:  * symbolic link needing interpretation is encountered.
                    484:  *
                    485:  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
                    486:  * whether the name is to be looked up, created, renamed, or deleted.
                    487:  * When CREATE, RENAME, or DELETE is specified, information usable in
                    488:  * creating, renaming, or deleting a directory entry may be calculated.
                    489:  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
1.72.2.3  tron      490:  * locked.  Otherwise the parent directory is not returned. If the target
                    491:  * of the pathname exists and LOCKLEAF is or'ed into the flag the target
                    492:  * is returned locked, otherwise it is returned unlocked.  When creating
                    493:  * or renaming and LOCKPARENT is specified, the target may not be ".".
                    494:  * When deleting and LOCKPARENT is specified, the target may be ".".
1.56      perry     495:  *
1.10      cgd       496:  * Overall outline of lookup:
                    497:  *
                    498:  * dirloop:
                    499:  *     identify next component of name at ndp->ni_ptr
                    500:  *     handle degenerate case where name is null string
                    501:  *     if .. and crossing mount points and on mounted filesys, find parent
                    502:  *     call VOP_LOOKUP routine for next component name
1.72.2.3  tron      503:  *         directory vnode returned in ni_dvp, locked.
1.10      cgd       504:  *         component vnode returned in ni_vp (if it exists), locked.
                    505:  *     if result vnode is mounted on and crossing mount points,
                    506:  *         find mounted on vnode
                    507:  *     if more components of name, do next level at dirloop
                    508:  *     return the answer in ni_vp, locked if LOCKLEAF set
                    509:  *         if LOCKPARENT set, return locked parent in ni_dvp
                    510:  */
1.12      mycroft   511: int
1.60      thorpej   512: lookup(struct nameidata *ndp)
1.10      cgd       513: {
1.33      augustss  514:        const char *cp;                 /* pointer into pathname argument */
                    515:        struct vnode *dp = 0;           /* the directory we are searching */
1.10      cgd       516:        struct vnode *tdp;              /* saved dp */
                    517:        struct mount *mp;               /* mount table entry */
                    518:        int docache;                    /* == 0 do not cache last component */
1.12      mycroft   519:        int rdonly;                     /* lookup read-only flag bit */
1.10      cgd       520:        int error = 0;
1.23      mycroft   521:        int slashes;
1.12      mycroft   522:        struct componentname *cnp = &ndp->ni_cnd;
1.64      christos  523:        struct lwp *l = cnp->cn_lwp;
1.10      cgd       524:
                    525:        /*
                    526:         * Setup: break out flag bits into variables.
                    527:         */
1.12      mycroft   528:        docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
1.72.2.3  tron      529:        if (cnp->cn_nameiop == DELETE)
1.10      cgd       530:                docache = 0;
1.12      mycroft   531:        rdonly = cnp->cn_flags & RDONLY;
1.10      cgd       532:        ndp->ni_dvp = NULL;
1.12      mycroft   533:        cnp->cn_flags &= ~ISSYMLINK;
1.10      cgd       534:        dp = ndp->ni_startdir;
                    535:        ndp->ni_startdir = NULLVP;
                    536:
1.23      mycroft   537:        /*
                    538:         * If we have a leading string of slashes, remove them, and just make
                    539:         * sure the current node is a directory.
                    540:         */
                    541:        cp = cnp->cn_nameptr;
                    542:        if (*cp == '/') {
                    543:                do {
                    544:                        cp++;
                    545:                } while (*cp == '/');
                    546:                ndp->ni_pathlen -= cp - cnp->cn_nameptr;
                    547:                cnp->cn_nameptr = cp;
                    548:
                    549:                if (dp->v_type != VDIR) {
                    550:                        error = ENOTDIR;
1.72.2.3  tron      551:                        vput(dp);
1.23      mycroft   552:                        goto bad;
                    553:                }
                    554:
                    555:                /*
                    556:                 * If we've exhausted the path name, then just return the
                    557:                 * current node.  If the caller requested the parent node (i.e.
                    558:                 * it's a CREATE, DELETE, or RENAME), and we don't have one
                    559:                 * (because this is the root directory), then we must fail.
                    560:                 */
                    561:                if (cnp->cn_nameptr[0] == '\0') {
1.72.2.3  tron      562:                        if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) {
1.65      chs       563:                                switch (cnp->cn_nameiop) {
                    564:                                case CREATE:
                    565:                                        error = EEXIST;
                    566:                                        break;
                    567:                                case DELETE:
                    568:                                case RENAME:
                    569:                                        error = EBUSY;
                    570:                                        break;
                    571:                                default:
                    572:                                        KASSERT(0);
                    573:                                }
1.72.2.3  tron      574:                                vput(dp);
1.23      mycroft   575:                                goto bad;
                    576:                        }
                    577:                        ndp->ni_vp = dp;
                    578:                        cnp->cn_flags |= ISLASTCN;
                    579:                        goto terminal;
                    580:                }
                    581:        }
                    582:
1.10      cgd       583: dirloop:
                    584:        /*
                    585:         * Search a new directory.
                    586:         *
1.12      mycroft   587:         * The cn_hash value is for use by vfs_cache.
1.10      cgd       588:         * The last component of the filename is left accessible via
1.12      mycroft   589:         * cnp->cn_nameptr for callers that need the name. Callers needing
1.10      cgd       590:         * the name set the SAVENAME flag. When done, they assume
                    591:         * responsibility for freeing the pathname buffer.
1.72.2.3  tron      592:         *
                    593:         * At this point, our only vnode state is that "dp" is held and locked.
1.10      cgd       594:         */
1.12      mycroft   595:        cnp->cn_consume = 0;
1.39      lukem     596:        cp = NULL;
                    597:        cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp);
1.12      mycroft   598:        cnp->cn_namelen = cp - cnp->cn_nameptr;
                    599:        if (cnp->cn_namelen > NAME_MAX) {
1.72.2.3  tron      600:                vput(dp);
1.10      cgd       601:                error = ENAMETOOLONG;
1.72.2.3  tron      602:                ndp->ni_dvp = NULL;
1.10      cgd       603:                goto bad;
                    604:        }
                    605: #ifdef NAMEI_DIAGNOSTIC
                    606:        { char c = *cp;
1.41      soren     607:        *(char *)cp = '\0';
1.19      christos  608:        printf("{%s}: ", cnp->cn_nameptr);
1.41      soren     609:        *(char *)cp = c; }
1.52      yamt      610: #endif /* NAMEI_DIAGNOSTIC */
1.12      mycroft   611:        ndp->ni_pathlen -= cnp->cn_namelen;
1.10      cgd       612:        ndp->ni_next = cp;
1.23      mycroft   613:        /*
                    614:         * If this component is followed by a slash, then move the pointer to
                    615:         * the next component forward, and remember that this component must be
                    616:         * a directory.
                    617:         */
                    618:        if (*cp == '/') {
                    619:                do {
                    620:                        cp++;
                    621:                } while (*cp == '/');
                    622:                slashes = cp - ndp->ni_next;
                    623:                ndp->ni_pathlen -= slashes;
                    624:                ndp->ni_next = cp;
                    625:                cnp->cn_flags |= REQUIREDIR;
                    626:        } else {
                    627:                slashes = 0;
                    628:                cnp->cn_flags &= ~REQUIREDIR;
                    629:        }
                    630:        /*
                    631:         * We do special processing on the last component, whether or not it's
                    632:         * a directory.  Cache all intervening lookups, but not the final one.
                    633:         */
                    634:        if (*cp == '\0') {
                    635:                if (docache)
                    636:                        cnp->cn_flags |= MAKEENTRY;
                    637:                else
                    638:                        cnp->cn_flags &= ~MAKEENTRY;
                    639:                cnp->cn_flags |= ISLASTCN;
                    640:        } else {
                    641:                cnp->cn_flags |= MAKEENTRY;
                    642:                cnp->cn_flags &= ~ISLASTCN;
                    643:        }
1.12      mycroft   644:        if (cnp->cn_namelen == 2 &&
                    645:            cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
                    646:                cnp->cn_flags |= ISDOTDOT;
                    647:        else
                    648:                cnp->cn_flags &= ~ISDOTDOT;
1.10      cgd       649:
                    650:        /*
                    651:         * Handle "..": two special cases.
                    652:         * 1. If at root directory (e.g. after chroot)
1.12      mycroft   653:         *    or at absolute root directory
1.10      cgd       654:         *    then ignore it so can't get out.
1.40      wrstuden  655:         * 1a. If we have somehow gotten out of a jail, warn
                    656:         *    and also ignore it so we can't get farther out.
1.10      cgd       657:         * 2. If this vnode is the root of a mounted
                    658:         *    filesystem, then replace it with the
                    659:         *    vnode which was mounted on so we take the
                    660:         *    .. in the other file system.
                    661:         */
1.12      mycroft   662:        if (cnp->cn_flags & ISDOTDOT) {
1.64      christos  663:                struct proc *p = l->l_proc;
                    664:
1.10      cgd       665:                for (;;) {
1.12      mycroft   666:                        if (dp == ndp->ni_rootdir || dp == rootvnode) {
1.10      cgd       667:                                ndp->ni_dvp = dp;
                    668:                                ndp->ni_vp = dp;
                    669:                                VREF(dp);
                    670:                                goto nextname;
1.40      wrstuden  671:                        }
                    672:                        if (ndp->ni_rootdir != rootvnode) {
                    673:                                int retval;
1.72.2.3  tron      674:
1.40      wrstuden  675:                                VOP_UNLOCK(dp, 0);
1.64      christos  676:                                retval = vn_isunder(dp, ndp->ni_rootdir, l);
1.40      wrstuden  677:                                vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
                    678:                                if (!retval) {
                    679:                                    /* Oops! We got out of jail! */
                    680:                                    log(LOG_WARNING,
                    681:                                        "chrooted pid %d uid %d (%s) "
                    682:                                        "detected outside of its chroot\n",
1.71      ad        683:                                        p->p_pid, kauth_cred_geteuid(l->l_cred),
1.64      christos  684:                                        p->p_comm);
1.40      wrstuden  685:                                    /* Put us at the jail root. */
                    686:                                    vput(dp);
                    687:                                    dp = ndp->ni_rootdir;
                    688:                                    ndp->ni_dvp = dp;
                    689:                                    ndp->ni_vp = dp;
                    690:                                    VREF(dp);
                    691:                                    VREF(dp);
                    692:                                    vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
                    693:                                    goto nextname;
                    694:                                }
1.10      cgd       695:                        }
                    696:                        if ((dp->v_flag & VROOT) == 0 ||
1.12      mycroft   697:                            (cnp->cn_flags & NOCROSSMOUNT))
1.10      cgd       698:                                break;
                    699:                        tdp = dp;
                    700:                        dp = dp->v_mount->mnt_vnodecovered;
                    701:                        vput(tdp);
                    702:                        VREF(dp);
1.26      fvdl      703:                        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.10      cgd       704:                }
                    705:        }
                    706:
                    707:        /*
                    708:         * We now have a segment name to search for, and a directory to search.
1.72.2.3  tron      709:         * Again, our only vnode state is that "dp" is held and locked.
1.10      cgd       710:         */
1.12      mycroft   711: unionlookup:
                    712:        ndp->ni_dvp = dp;
1.26      fvdl      713:        ndp->ni_vp = NULL;
1.72.2.3  tron      714:        error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp);
                    715:        if (error != 0) {
1.10      cgd       716: #ifdef DIAGNOSTIC
                    717:                if (ndp->ni_vp != NULL)
1.43      christos  718:                        panic("leaf `%s' should be empty", cnp->cn_nameptr);
1.52      yamt      719: #endif /* DIAGNOSTIC */
1.10      cgd       720: #ifdef NAMEI_DIAGNOSTIC
1.19      christos  721:                printf("not found\n");
1.52      yamt      722: #endif /* NAMEI_DIAGNOSTIC */
1.12      mycroft   723:                if ((error == ENOENT) &&
1.10      cgd       724:                    (dp->v_flag & VROOT) &&
                    725:                    (dp->v_mount->mnt_flag & MNT_UNION)) {
                    726:                        tdp = dp;
                    727:                        dp = dp->v_mount->mnt_vnodecovered;
1.72.2.3  tron      728:                        vput(tdp);
1.10      cgd       729:                        VREF(dp);
1.26      fvdl      730:                        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.12      mycroft   731:                        goto unionlookup;
1.10      cgd       732:                }
1.12      mycroft   733:
1.10      cgd       734:                if (error != EJUSTRETURN)
                    735:                        goto bad;
1.72.2.3  tron      736:
1.10      cgd       737:                /*
1.23      mycroft   738:                 * If this was not the last component, or there were trailing
1.51      christos  739:                 * slashes, and we are not going to create a directory,
                    740:                 * then the name must exist.
1.23      mycroft   741:                 */
1.51      christos  742:                if ((cnp->cn_flags & (REQUIREDIR | CREATEDIR)) == REQUIREDIR) {
1.23      mycroft   743:                        error = ENOENT;
                    744:                        goto bad;
                    745:                }
1.72.2.3  tron      746:
1.23      mycroft   747:                /*
1.10      cgd       748:                 * If creating and at end of pathname, then can consider
                    749:                 * allowing file to be created.
                    750:                 */
1.26      fvdl      751:                if (rdonly) {
1.10      cgd       752:                        error = EROFS;
                    753:                        goto bad;
                    754:                }
1.72.2.3  tron      755:
1.10      cgd       756:                /*
                    757:                 * We return with ni_vp NULL to indicate that the entry
                    758:                 * doesn't currently exist, leaving a pointer to the
1.69      rumble    759:                 * (possibly locked) directory vnode in ndp->ni_dvp.
1.10      cgd       760:                 */
1.12      mycroft   761:                if (cnp->cn_flags & SAVESTART) {
1.10      cgd       762:                        ndp->ni_startdir = ndp->ni_dvp;
                    763:                        VREF(ndp->ni_startdir);
                    764:                }
                    765:                return (0);
                    766:        }
                    767: #ifdef NAMEI_DIAGNOSTIC
1.19      christos  768:        printf("found\n");
1.52      yamt      769: #endif /* NAMEI_DIAGNOSTIC */
1.10      cgd       770:
1.12      mycroft   771:        /*
1.23      mycroft   772:         * Take into account any additional components consumed by the
                    773:         * underlying filesystem.  This will include any trailing slashes after
                    774:         * the last component consumed.
1.12      mycroft   775:         */
                    776:        if (cnp->cn_consume > 0) {
1.23      mycroft   777:                ndp->ni_pathlen -= cnp->cn_consume - slashes;
                    778:                ndp->ni_next += cnp->cn_consume - slashes;
1.12      mycroft   779:                cnp->cn_consume = 0;
1.23      mycroft   780:                if (ndp->ni_next[0] == '\0')
                    781:                        cnp->cn_flags |= ISLASTCN;
1.12      mycroft   782:        }
                    783:
1.10      cgd       784:        dp = ndp->ni_vp;
1.72.2.3  tron      785:
                    786:        /*
                    787:         * "dp" and "ndp->ni_dvp" are both locked and held,
                    788:         * and may be the same vnode.
                    789:         */
                    790:
1.10      cgd       791:        /*
                    792:         * Check to see if the vnode has been mounted on;
                    793:         * if so find the root of the mounted file system.
                    794:         */
                    795:        while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
1.12      mycroft   796:               (cnp->cn_flags & NOCROSSMOUNT) == 0) {
1.26      fvdl      797:                if (vfs_busy(mp, 0, 0))
1.12      mycroft   798:                        continue;
1.72.2.3  tron      799:
                    800:                KASSERT(ndp->ni_dvp != dp);
                    801:                VOP_UNLOCK(ndp->ni_dvp, 0);
                    802:                vput(dp);
1.47      thorpej   803:                error = VFS_ROOT(mp, &tdp);
1.26      fvdl      804:                vfs_unbusy(mp);
1.32      wrstuden  805:                if (error) {
1.72.2.3  tron      806:                        vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
                    807:                        goto bad;
1.32      wrstuden  808:                }
1.72.2.3  tron      809:                VOP_UNLOCK(tdp, 0);
1.10      cgd       810:                ndp->ni_vp = dp = tdp;
1.72.2.3  tron      811:                vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
                    812:                vn_lock(ndp->ni_vp, LK_EXCLUSIVE | LK_RETRY);
1.14      mycroft   813:        }
                    814:
                    815:        /*
1.23      mycroft   816:         * Check for symbolic link.  Back up over any slashes that we skipped,
                    817:         * as we will need them again.
1.14      mycroft   818:         */
1.23      mycroft   819:        if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
                    820:                ndp->ni_pathlen += slashes;
                    821:                ndp->ni_next -= slashes;
1.14      mycroft   822:                cnp->cn_flags |= ISSYMLINK;
                    823:                return (0);
1.10      cgd       824:        }
                    825:
1.23      mycroft   826:        /*
                    827:         * Check for directory, if the component was followed by a series of
                    828:         * slashes.
                    829:         */
                    830:        if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
                    831:                error = ENOTDIR;
1.72.2.3  tron      832:                KASSERT(dp != ndp->ni_dvp);
                    833:                vput(dp);
                    834:                goto bad;
1.23      mycroft   835:        }
                    836:
1.10      cgd       837: nextname:
1.72.2.3  tron      838:
1.10      cgd       839:        /*
1.23      mycroft   840:         * Not a symbolic link.  If this was not the last component, then
                    841:         * continue at the next component, else return.
1.10      cgd       842:         */
1.23      mycroft   843:        if (!(cnp->cn_flags & ISLASTCN)) {
1.12      mycroft   844:                cnp->cn_nameptr = ndp->ni_next;
1.72.2.3  tron      845:                if (ndp->ni_dvp == dp) {
                    846:                        vrele(ndp->ni_dvp);
                    847:                } else {
                    848:                        vput(ndp->ni_dvp);
                    849:                }
1.10      cgd       850:                goto dirloop;
                    851:        }
1.23      mycroft   852:
                    853: terminal:
1.72.2.3  tron      854:
1.10      cgd       855:        /*
1.26      fvdl      856:         * Disallow directory write attempts on read-only file systems.
1.10      cgd       857:         */
1.26      fvdl      858:        if (rdonly &&
                    859:            (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
1.72.2.3  tron      860:
1.10      cgd       861:                /*
                    862:                 * Disallow directory write attempts on read-only
                    863:                 * file systems.
                    864:                 */
1.26      fvdl      865:                error = EROFS;
1.72.2.3  tron      866:                if (dp != ndp->ni_dvp) {
                    867:                        vput(dp);
                    868:                }
                    869:                goto bad;
1.10      cgd       870:        }
1.23      mycroft   871:        if (ndp->ni_dvp != NULL) {
                    872:                if (cnp->cn_flags & SAVESTART) {
                    873:                        ndp->ni_startdir = ndp->ni_dvp;
                    874:                        VREF(ndp->ni_startdir);
                    875:                }
1.10      cgd       876:        }
1.72.2.3  tron      877:        if ((cnp->cn_flags & LOCKLEAF) == 0) {
1.26      fvdl      878:                VOP_UNLOCK(dp, 0);
1.72.2.3  tron      879:        }
1.10      cgd       880:        return (0);
                    881:
                    882: bad:
                    883:        ndp->ni_vp = NULL;
1.12      mycroft   884:        return (error);
                    885: }
                    886:
                    887: /*
                    888:  * Reacquire a path name component.
1.72.2.3  tron      889:  * dvp is locked on entry and exit.
                    890:  * *vpp is locked on exit unless it's NULL.
1.12      mycroft   891:  */
                    892: int
1.60      thorpej   893: relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
1.12      mycroft   894: {
                    895:        int rdonly;                     /* lookup read-only flag bit */
                    896:        int error = 0;
1.52      yamt      897: #ifdef DEBUG
1.72.2.3  tron      898:        uint32_t newhash;               /* DEBUG: check name hash */
1.41      soren     899:        const char *cp;                 /* DEBUG: check name ptr/len */
1.52      yamt      900: #endif /* DEBUG */
1.12      mycroft   901:
                    902:        /*
                    903:         * Setup: break out flag bits into variables.
                    904:         */
                    905:        rdonly = cnp->cn_flags & RDONLY;
                    906:        cnp->cn_flags &= ~ISSYMLINK;
                    907:
                    908:        /*
                    909:         * Search a new directory.
                    910:         *
                    911:         * The cn_hash value is for use by vfs_cache.
                    912:         * The last component of the filename is left accessible via
                    913:         * cnp->cn_nameptr for callers that need the name. Callers needing
                    914:         * the name set the SAVENAME flag. When done, they assume
                    915:         * responsibility for freeing the pathname buffer.
                    916:         */
1.52      yamt      917: #ifdef DEBUG
1.39      lukem     918:        cp = NULL;
                    919:        newhash = namei_hash(cnp->cn_nameptr, &cp);
1.72.2.3  tron      920:        if ((uint32_t)newhash != (uint32_t)cnp->cn_hash)
1.12      mycroft   921:                panic("relookup: bad hash");
                    922:        if (cnp->cn_namelen != cp - cnp->cn_nameptr)
1.58      christos  923:                panic("relookup: bad len");
1.53      yamt      924:        while (*cp == '/')
                    925:                cp++;
1.12      mycroft   926:        if (*cp != 0)
                    927:                panic("relookup: not last component");
1.52      yamt      928: #endif /* DEBUG */
1.12      mycroft   929:
                    930:        /*
                    931:         * Check for degenerate name (e.g. / or "")
                    932:         * which is a way of talking about a directory,
                    933:         * e.g. like "/." or ".".
                    934:         */
1.23      mycroft   935:        if (cnp->cn_nameptr[0] == '\0')
                    936:                panic("relookup: null name");
1.12      mycroft   937:
                    938:        if (cnp->cn_flags & ISDOTDOT)
1.58      christos  939:                panic("relookup: lookup on dot-dot");
1.12      mycroft   940:
                    941:        /*
                    942:         * We now have a segment name to search for, and a directory to search.
                    943:         */
1.72.2.4! riz       944:        *vpp = NULL;
1.72.2.3  tron      945:        if ((error = VOP_LOOKUP(dvp, vpp, cnp)) != 0) {
1.12      mycroft   946: #ifdef DIAGNOSTIC
                    947:                if (*vpp != NULL)
1.43      christos  948:                        panic("leaf `%s' should be empty", cnp->cn_nameptr);
1.12      mycroft   949: #endif
                    950:                if (error != EJUSTRETURN)
                    951:                        goto bad;
                    952:        }
                    953:
                    954: #ifdef DIAGNOSTIC
                    955:        /*
                    956:         * Check for symbolic link
                    957:         */
1.72.2.3  tron      958:        if (*vpp && (*vpp)->v_type == VLNK && (cnp->cn_flags & FOLLOW))
1.58      christos  959:                panic("relookup: symlink found");
1.12      mycroft   960: #endif
                    961:
                    962:        /*
                    963:         * Check for read-only file systems.
                    964:         */
1.72.2.3  tron      965:        if (rdonly && cnp->cn_nameiop != LOOKUP) {
1.26      fvdl      966:                error = EROFS;
1.72.2.3  tron      967:                if (*vpp) {
                    968:                        vput(*vpp);
                    969:                }
                    970:                goto bad;
1.12      mycroft   971:        }
                    972:        if (cnp->cn_flags & SAVESTART)
                    973:                VREF(dvp);
                    974:        return (0);
                    975:
                    976: bad:
                    977:        *vpp = NULL;
1.10      cgd       978:        return (error);
                    979: }

CVSweb <webmaster@jp.NetBSD.org>