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