17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*d67944fbSScott Rotondo * Common Development and Distribution License (the "License").
6*d67944fbSScott Rotondo * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21*d67944fbSScott Rotondo
227c478bd9Sstevel@tonic-gate /*
23*d67944fbSScott Rotondo * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
287c478bd9Sstevel@tonic-gate /* All Rights Reserved */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD
327c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California.
337c478bd9Sstevel@tonic-gate */
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate /*
367c478bd9Sstevel@tonic-gate * This file contains the file lookup code for NFS.
377c478bd9Sstevel@tonic-gate */
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
407c478bd9Sstevel@tonic-gate #include "brpc.h"
417c478bd9Sstevel@tonic-gate #include <rpc/types.h>
427c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
437c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
447c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h>
457c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
467c478bd9Sstevel@tonic-gate #include "clnt.h"
477c478bd9Sstevel@tonic-gate #include <rpcsvc/mount.h>
48*d67944fbSScott Rotondo #include <st_pathname.h>
497c478bd9Sstevel@tonic-gate #include <sys/errno.h>
507c478bd9Sstevel@tonic-gate #include <sys/promif.h>
517c478bd9Sstevel@tonic-gate #include "nfs_inet.h"
527c478bd9Sstevel@tonic-gate #include "socket_inet.h"
537c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h>
547c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h>
557c478bd9Sstevel@tonic-gate #include <sys/types.h>
567c478bd9Sstevel@tonic-gate #include <sys/salib.h>
577c478bd9Sstevel@tonic-gate #include <sys/sacache.h>
587c478bd9Sstevel@tonic-gate #include <sys/stat.h>
597c478bd9Sstevel@tonic-gate #include <sys/bootvfs.h>
607c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h>
617c478bd9Sstevel@tonic-gate #include "mac.h"
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate static int root_inum = 1; /* Dummy i-node number for root */
647c478bd9Sstevel@tonic-gate static int next_inum = 1; /* Next dummy i-node number */
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate #define dprintf if (boothowto & RB_DEBUG) printf
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate * starting at current directory (root for us), lookup the pathname.
707c478bd9Sstevel@tonic-gate * return the file handle of said file.
717c478bd9Sstevel@tonic-gate */
727c478bd9Sstevel@tonic-gate
73*d67944fbSScott Rotondo static int stlookuppn(struct st_pathname *pnp, struct nfs_file *cfile,
747c478bd9Sstevel@tonic-gate bool_t needroothandle);
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate * For NFSv4 we may be calling lookup in the context of evaluating the
787c478bd9Sstevel@tonic-gate * root path. In this case we set needroothandle to TRUE.
797c478bd9Sstevel@tonic-gate */
807c478bd9Sstevel@tonic-gate int
lookup(char * pathname,struct nfs_file * cur_file,bool_t needroothandle)817c478bd9Sstevel@tonic-gate lookup(char *pathname, struct nfs_file *cur_file, bool_t needroothandle)
827c478bd9Sstevel@tonic-gate {
83*d67944fbSScott Rotondo struct st_pathname pnp;
847c478bd9Sstevel@tonic-gate int error;
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate static char lkup_path[NFS_MAXPATHLEN]; /* pn_alloc doesn't */
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate pnp.pn_buf = &lkup_path[0];
897c478bd9Sstevel@tonic-gate bzero(pnp.pn_buf, NFS_MAXPATHLEN);
90*d67944fbSScott Rotondo error = stpn_get(pathname, &pnp);
917c478bd9Sstevel@tonic-gate if (error)
927c478bd9Sstevel@tonic-gate return (error);
93*d67944fbSScott Rotondo error = stlookuppn(&pnp, cur_file, needroothandle);
947c478bd9Sstevel@tonic-gate return (error);
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate static int
stlookuppn(struct st_pathname * pnp,struct nfs_file * cfile,bool_t needroothandle)98*d67944fbSScott Rotondo stlookuppn(struct st_pathname *pnp, struct nfs_file *cfile,
99*d67944fbSScott Rotondo bool_t needroothandle)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate char component[NFS_MAXNAMLEN+1]; /* buffer for component */
1027c478bd9Sstevel@tonic-gate int nlink = 0;
1037c478bd9Sstevel@tonic-gate int error = 0;
1047c478bd9Sstevel@tonic-gate int dino, cino;
1057c478bd9Sstevel@tonic-gate struct nfs_file *cdp = NULL;
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate *cfile = roothandle; /* structure copy - start at the root. */
1087c478bd9Sstevel@tonic-gate dino = root_inum;
1097c478bd9Sstevel@tonic-gate begin:
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate * Each time we begin a new name interpretation (e.g.
1127c478bd9Sstevel@tonic-gate * when first called and after each symbolic link is
1137c478bd9Sstevel@tonic-gate * substituted), we allow the search to start at the
1147c478bd9Sstevel@tonic-gate * root directory if the name starts with a '/', otherwise
1157c478bd9Sstevel@tonic-gate * continuing from the current directory.
1167c478bd9Sstevel@tonic-gate */
1177c478bd9Sstevel@tonic-gate component[0] = '\0';
118*d67944fbSScott Rotondo if (stpn_peekchar(pnp) == '/') {
1197c478bd9Sstevel@tonic-gate if (!needroothandle)
1207c478bd9Sstevel@tonic-gate *cfile = roothandle;
1217c478bd9Sstevel@tonic-gate dino = root_inum;
122*d67944fbSScott Rotondo stpn_skipslash(pnp);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate next:
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate * Make sure we have a directory.
1287c478bd9Sstevel@tonic-gate */
1297c478bd9Sstevel@tonic-gate if (!cfile_is_dir(cfile)) {
1307c478bd9Sstevel@tonic-gate error = ENOTDIR;
1317c478bd9Sstevel@tonic-gate goto bad;
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate /*
1347c478bd9Sstevel@tonic-gate * Process the next component of the pathname.
1357c478bd9Sstevel@tonic-gate */
136*d67944fbSScott Rotondo error = stpn_stripcomponent(pnp, component);
1377c478bd9Sstevel@tonic-gate if (error)
1387c478bd9Sstevel@tonic-gate goto bad;
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate /*
1417c478bd9Sstevel@tonic-gate * Check for degenerate name (e.g. / or "")
1427c478bd9Sstevel@tonic-gate * which is a way of talking about a directory,
1437c478bd9Sstevel@tonic-gate * e.g. "/." or ".".
1447c478bd9Sstevel@tonic-gate */
1457c478bd9Sstevel@tonic-gate if (component[0] == '\0')
1467c478bd9Sstevel@tonic-gate return (0);
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate * Handle "..": two special cases.
1507c478bd9Sstevel@tonic-gate * 1. If at root directory (e.g. after chroot)
1517c478bd9Sstevel@tonic-gate * then ignore it so can't get out.
1527c478bd9Sstevel@tonic-gate * 2. If this vnode is the root of a mounted
1537c478bd9Sstevel@tonic-gate * file system, then replace it with the
1547c478bd9Sstevel@tonic-gate * vnode which was mounted on so we take the
1557c478bd9Sstevel@tonic-gate * .. in the other file system.
1567c478bd9Sstevel@tonic-gate */
1577c478bd9Sstevel@tonic-gate if (strcmp(component, "..") == 0) {
1587c478bd9Sstevel@tonic-gate if (cfile == &roothandle)
1597c478bd9Sstevel@tonic-gate goto skip;
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate
1627c478bd9Sstevel@tonic-gate /*
1637c478bd9Sstevel@tonic-gate * Perform a lookup in the current directory.
1647c478bd9Sstevel@tonic-gate * We create a simple negative lookup cache by storing
1657c478bd9Sstevel@tonic-gate * inode -1 to indicate file not found.
1667c478bd9Sstevel@tonic-gate */
1677c478bd9Sstevel@tonic-gate cino = get_dcache(mac_get_dev(), component, dino);
1687c478bd9Sstevel@tonic-gate if (cino == -1)
1697c478bd9Sstevel@tonic-gate return (ENOENT);
1707c478bd9Sstevel@tonic-gate #ifdef DEBUG
1717c478bd9Sstevel@tonic-gate dprintf("lookup: component %s pathleft %s\n", component, pnp->pn_path);
1727c478bd9Sstevel@tonic-gate #endif
1737c478bd9Sstevel@tonic-gate if ((cino == 0) ||
174*d67944fbSScott Rotondo ((cdp = (struct nfs_file *)get_icache(mac_get_dev(), cino)) == 0)) {
1757c478bd9Sstevel@tonic-gate struct nfs_file *lkp;
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate /*
1787c478bd9Sstevel@tonic-gate * If an RPC error occurs, error is not changed,
1797c478bd9Sstevel@tonic-gate * else it is the NFS error if NULL is returned.
1807c478bd9Sstevel@tonic-gate */
1817c478bd9Sstevel@tonic-gate error = -1;
1827c478bd9Sstevel@tonic-gate switch (cfile->version) {
1837c478bd9Sstevel@tonic-gate case NFS_VERSION:
1847c478bd9Sstevel@tonic-gate lkp = nfslookup(cfile, component, &error);
1857c478bd9Sstevel@tonic-gate break;
1867c478bd9Sstevel@tonic-gate case NFS_V3:
1877c478bd9Sstevel@tonic-gate lkp = nfs3lookup(cfile, component, &error);
1887c478bd9Sstevel@tonic-gate break;
1897c478bd9Sstevel@tonic-gate case NFS_V4:
1907c478bd9Sstevel@tonic-gate lkp = nfs4lookup(cfile, component, &error);
1917c478bd9Sstevel@tonic-gate break;
1927c478bd9Sstevel@tonic-gate default:
1937c478bd9Sstevel@tonic-gate printf("lookup: NFS Version %d not supported\n",
1947c478bd9Sstevel@tonic-gate cfile->version);
1957c478bd9Sstevel@tonic-gate lkp = NULL;
1967c478bd9Sstevel@tonic-gate break;
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate /*
2007c478bd9Sstevel@tonic-gate * Check for RPC error
2017c478bd9Sstevel@tonic-gate */
2027c478bd9Sstevel@tonic-gate if (error == -1) {
2037c478bd9Sstevel@tonic-gate printf("lookup: lookup RPC error\n");
2047c478bd9Sstevel@tonic-gate return (error);
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate /*
2087c478bd9Sstevel@tonic-gate * Check for NFS error
2097c478bd9Sstevel@tonic-gate */
2107c478bd9Sstevel@tonic-gate if (lkp == NULL) {
2117c478bd9Sstevel@tonic-gate if ((error != NFSERR_NOENT) &&
2127c478bd9Sstevel@tonic-gate (error != NFS3ERR_NOENT) &&
2137c478bd9Sstevel@tonic-gate (error != NFS4ERR_NOENT)) {
2147c478bd9Sstevel@tonic-gate #ifdef DEBUG
2157c478bd9Sstevel@tonic-gate dprintf("lookup: lkp is NULL with error %d\n", error);
2167c478bd9Sstevel@tonic-gate #endif
2177c478bd9Sstevel@tonic-gate return (error);
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate #ifdef DEBUG
2207c478bd9Sstevel@tonic-gate dprintf("lookup: lkp is NULL with error %d\n", error);
2217c478bd9Sstevel@tonic-gate #endif
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate * File not found so set cached inode to -1
2247c478bd9Sstevel@tonic-gate */
2257c478bd9Sstevel@tonic-gate set_dcache(mac_get_dev(), component, dino, -1);
2267c478bd9Sstevel@tonic-gate return (error);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate if (cdp = (struct nfs_file *)
2307c478bd9Sstevel@tonic-gate bkmem_alloc(sizeof (struct nfs_file))) {
2317c478bd9Sstevel@tonic-gate /*
2327c478bd9Sstevel@tonic-gate * Save this entry in cache for next time ...
2337c478bd9Sstevel@tonic-gate */
2347c478bd9Sstevel@tonic-gate if (!cino)
2357c478bd9Sstevel@tonic-gate cino = ++next_inum;
2367c478bd9Sstevel@tonic-gate *cdp = *lkp;
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate set_dcache(mac_get_dev(), component, dino, cino);
2397c478bd9Sstevel@tonic-gate set_icache(mac_get_dev(), cino, cdp,
2407c478bd9Sstevel@tonic-gate sizeof (struct nfs_file));
2417c478bd9Sstevel@tonic-gate } else {
2427c478bd9Sstevel@tonic-gate /*
2437c478bd9Sstevel@tonic-gate * Out of memory, clear cache keys so we don't get
2447c478bd9Sstevel@tonic-gate * confused later.
2457c478bd9Sstevel@tonic-gate */
2467c478bd9Sstevel@tonic-gate cino = 0;
2477c478bd9Sstevel@tonic-gate cdp = lkp;
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate dino = cino;
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate /*
2537c478bd9Sstevel@tonic-gate * If we hit a symbolic link and there is more path to be
2547c478bd9Sstevel@tonic-gate * translated or this operation does not wish to apply
2557c478bd9Sstevel@tonic-gate * to a link, then place the contents of the link at the
2567c478bd9Sstevel@tonic-gate * front of the remaining pathname.
2577c478bd9Sstevel@tonic-gate */
2587c478bd9Sstevel@tonic-gate if (cfile_is_lnk(cdp)) {
259*d67944fbSScott Rotondo struct st_pathname linkpath;
2607c478bd9Sstevel@tonic-gate static char path_tmp[NFS_MAXPATHLEN]; /* used for symlinks */
2617c478bd9Sstevel@tonic-gate char *pathp;
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate linkpath.pn_buf = &path_tmp[0];
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate nlink++;
2667c478bd9Sstevel@tonic-gate if (nlink > MAXSYMLINKS) {
2677c478bd9Sstevel@tonic-gate error = ELOOP;
2687c478bd9Sstevel@tonic-gate goto bad;
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate switch (cdp->version) {
2717c478bd9Sstevel@tonic-gate case NFS_VERSION:
2727c478bd9Sstevel@tonic-gate error = nfsgetsymlink(cdp, &pathp);
2737c478bd9Sstevel@tonic-gate break;
2747c478bd9Sstevel@tonic-gate case NFS_V3:
2757c478bd9Sstevel@tonic-gate error = nfs3getsymlink(cdp, &pathp);
2767c478bd9Sstevel@tonic-gate break;
2777c478bd9Sstevel@tonic-gate case NFS_V4:
2787c478bd9Sstevel@tonic-gate error = nfs4getsymlink(cdp, &pathp);
2797c478bd9Sstevel@tonic-gate break;
2807c478bd9Sstevel@tonic-gate default:
2817c478bd9Sstevel@tonic-gate printf("getsymlink: NFS Version %d not supported\n",
2827c478bd9Sstevel@tonic-gate cdp->version);
2837c478bd9Sstevel@tonic-gate error = ENOTSUP;
2847c478bd9Sstevel@tonic-gate break;
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate if (error)
2887c478bd9Sstevel@tonic-gate goto bad;
2897c478bd9Sstevel@tonic-gate
290*d67944fbSScott Rotondo stpn_get(pathp, &linkpath);
2917c478bd9Sstevel@tonic-gate
292*d67944fbSScott Rotondo if (stpn_pathleft(&linkpath) == 0)
293*d67944fbSScott Rotondo (void) stpn_set(&linkpath, ".");
294*d67944fbSScott Rotondo error = stpn_combine(pnp, &linkpath); /* linkpath before pn */
2957c478bd9Sstevel@tonic-gate if (error)
2967c478bd9Sstevel@tonic-gate goto bad;
2977c478bd9Sstevel@tonic-gate goto begin;
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate if (needroothandle) {
3017c478bd9Sstevel@tonic-gate roothandle = *cdp;
3027c478bd9Sstevel@tonic-gate needroothandle = FALSE;
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate *cfile = *cdp;
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate skip:
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate * Skip to next component of the pathname.
3097c478bd9Sstevel@tonic-gate * If no more components, return last directory (if wanted) and
3107c478bd9Sstevel@tonic-gate * last component (if wanted).
3117c478bd9Sstevel@tonic-gate */
312*d67944fbSScott Rotondo if (stpn_pathleft(pnp) == 0) {
313*d67944fbSScott Rotondo (void) stpn_set(pnp, component);
3147c478bd9Sstevel@tonic-gate return (0);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate /*
3177c478bd9Sstevel@tonic-gate * skip over slashes from end of last component
3187c478bd9Sstevel@tonic-gate */
319*d67944fbSScott Rotondo stpn_skipslash(pnp);
3207c478bd9Sstevel@tonic-gate goto next;
3217c478bd9Sstevel@tonic-gate bad:
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate * Error.
3247c478bd9Sstevel@tonic-gate */
3257c478bd9Sstevel@tonic-gate return (error);
3267c478bd9Sstevel@tonic-gate }
327