1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * Subdirectory detection: needed by exportfs and rpc.mountd. 44 * The above programs call issubdir() frequently, so we make 45 * it fast by caching the results of stat(). 46 */ 47 #include <sys/types.h> 48 #include <sys/param.h> 49 #include <sys/stat.h> 50 #include <string.h> 51 52 #define MAXSTATS MAXPATHLEN/2 /* maximum number of stat()'s to save */ 53 54 #define inoeq(ino1, ino2) ((ino1) == (ino2)) 55 #define deveq(dev1, dev2) ((dev1) == (dev2)) 56 57 /* 58 * dir1 is a subdirectory of dir2 within the same filesystem if 59 * (a) dir1 is identical to dir2 60 * (b) dir1's parent is dir2 61 */ 62 int 63 issubdir(dir1, dir2) 64 char *dir1; 65 char *dir2; 66 { 67 struct stat st; 68 struct stat parent_st; 69 char *p; 70 int index; 71 72 static dev_t child_dev; 73 static dev_t child_rdev; 74 static ino_t child_ino[MAXSTATS]; 75 static int valid; 76 static char childdir[MAXPATHLEN]; 77 static char child_fstype[_ST_FSTYPSZ]; 78 79 /* 80 * Get parent directory info 81 */ 82 if (stat(dir2, &parent_st) < 0) { 83 return (0); 84 } 85 86 if (strcmp(childdir, dir1) != 0) { 87 /* 88 * Not in cache: get child directory info 89 */ 90 p = strcpy(childdir, dir1) + strlen(dir1); 91 index = 0; 92 valid = 0; 93 for (;;) { 94 if (stat(childdir, &st) < 0) { 95 childdir[0] = 0; /* invalidate cache */ 96 return (0); 97 } 98 if (index == 0) { 99 child_dev = st.st_dev; 100 child_rdev = st.st_rdev; 101 (void) strncpy(child_fstype, st.st_fstype, 102 sizeof (child_fstype)); 103 } 104 if (index > 0 && 105 (child_dev != st.st_dev || 106 inoeq(child_ino[index - 1], st.st_ino))) { 107 /* 108 * Hit root: done 109 */ 110 break; 111 } 112 child_ino[index++] = st.st_ino; 113 if (S_ISDIR(st.st_mode)) { 114 p = strcpy(p, "/..") + 3; 115 } else { 116 p = strrchr(childdir, '/'); 117 if (p == NULL) { 118 p = strcpy(childdir, ".") + 1; 119 } else { 120 while (((p - 1) > childdir) && 121 *(p - 1) == '/') { 122 p--; 123 } 124 *p = '\0'; 125 } 126 } 127 } 128 valid = index; 129 (void) strcpy(childdir, dir1); 130 } 131 132 /* 133 * Perform the test 134 */ 135 if (!deveq(parent_st.st_dev, child_dev)) { 136 return (0); 137 } 138 139 /* 140 * Check rdev also in case of lofs 141 */ 142 if (((strcmp(parent_st.st_fstype, "lofs") == 0)) && 143 (strcmp(child_fstype, "lofs") == 0)) { 144 if (!deveq(parent_st.st_rdev, child_rdev)) { 145 return (0); 146 } 147 } 148 149 for (index = 0; index < valid; index++) { 150 if (inoeq(child_ino[index], parent_st.st_ino)) { 151 return (1); 152 } 153 } 154 return (0); 155 } 156