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 /*
41  * Subdirectory detection: needed by exportfs and rpc.mountd.
42  * The above programs call issubdir() frequently, so we make
43  * it fast by caching the results of stat().
44  */
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/stat.h>
48 #include <string.h>
49 
50 #define	MAXSTATS MAXPATHLEN/2	/* maximum number of stat()'s to save */
51 
52 #define	inoeq(ino1, ino2)	((ino1) == (ino2))
53 #define	deveq(dev1, dev2)	((dev1) == (dev2))
54 
55 /*
56  * dir1 is a subdirectory of dir2 within the same filesystem if
57  *     (a) dir1 is identical to dir2
58  *     (b) dir1's parent is dir2
59  */
60 int
issubdir(dir1,dir2)61 issubdir(dir1, dir2)
62 	char *dir1;
63 	char *dir2;
64 {
65 	struct stat st;
66 	struct stat parent_st;
67 	char *p;
68 	int index;
69 
70 	static dev_t child_dev;
71 	static dev_t child_rdev;
72 	static ino_t child_ino[MAXSTATS];
73 	static int valid;
74 	static char childdir[MAXPATHLEN];
75 	static char child_fstype[_ST_FSTYPSZ];
76 
77 	/*
78 	 * Get parent directory info
79 	 */
80 	if (stat(dir2, &parent_st) < 0) {
81 		return (0);
82 	}
83 
84 	if (strcmp(childdir, dir1) != 0) {
85 		/*
86 		 * Not in cache: get child directory info
87 		 */
88 		p = strcpy(childdir, dir1) + strlen(dir1);
89 		index = 0;
90 		valid = 0;
91 		for (;;) {
92 			if (stat(childdir, &st) < 0) {
93 				childdir[0] = 0;	/* invalidate cache */
94 				return (0);
95 			}
96 			if (index == 0) {
97 				child_dev = st.st_dev;
98 				child_rdev = st.st_rdev;
99 				(void) strncpy(child_fstype, st.st_fstype,
100 						sizeof (child_fstype));
101 			}
102 			if (index > 0 &&
103 			    (child_dev != st.st_dev ||
104 				inoeq(child_ino[index - 1], st.st_ino))) {
105 				/*
106 				 * Hit root: done
107 				 */
108 				break;
109 			}
110 			child_ino[index++] = st.st_ino;
111 			if (S_ISDIR(st.st_mode)) {
112 				p = strcpy(p, "/..") + 3;
113 			} else {
114 				p = strrchr(childdir, '/');
115 				if (p == NULL) {
116 					p = strcpy(childdir, ".") + 1;
117 				} else {
118 					while (((p - 1) > childdir) &&
119 						*(p - 1) == '/') {
120 						p--;
121 					}
122 					*p = '\0';
123 				}
124 			}
125 		}
126 		valid = index;
127 		(void) strcpy(childdir, dir1);
128 	}
129 
130 	/*
131 	 * Perform the test
132 	 */
133 	if (!deveq(parent_st.st_dev, child_dev)) {
134 		return (0);
135 	}
136 
137 	/*
138 	 * Check rdev also in case of lofs
139 	 */
140 	if (((strcmp(parent_st.st_fstype, "lofs") == 0)) &&
141 		(strcmp(child_fstype, "lofs") == 0)) {
142 		if (!deveq(parent_st.st_rdev, child_rdev)) {
143 			return (0);
144 		}
145 	}
146 
147 	for (index = 0; index < valid; index++) {
148 		if (inoeq(child_ino[index], parent_st.st_ino)) {
149 			return (1);
150 		}
151 	}
152 	return (0);
153 }
154