xref: /illumos-gate/usr/src/stand/lib/fs/nfs/lookup.c (revision d67944fbe3fa0b31893a7116a09b0718eecf6078)
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
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
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",
194*d67944fbSScott Rotondo 			    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",
282*d67944fbSScott Rotondo 			    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