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