xref: /illumos-gate/usr/src/uts/common/syscall/statvfs.c (revision 88f8b78a88cbdc6d8c1af5c3e54bc49d25095c98)
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 2001 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 /*
38  * Get file system statistics (statvfs and fstatvfs).
39  */
40 
41 #include <sys/types.h>
42 #include <sys/inttypes.h>
43 #include <sys/t_lock.h>
44 #include <sys/param.h>
45 #include <sys/errno.h>
46 #include <sys/fstyp.h>
47 #include <sys/systm.h>
48 #include <sys/vfs.h>
49 #include <sys/statvfs.h>
50 #include <sys/vnode.h>
51 #include <sys/file.h>
52 #include <sys/cmn_err.h>
53 #include <sys/debug.h>
54 #include <sys/pathname.h>
55 
56 #include <vm/page.h>
57 
58 #define	STATVFSCOPY(dst, src)					\
59 	(dst)->f_bsize	= (src)->f_bsize;			\
60 	(dst)->f_frsize	= (src)->f_frsize;			\
61 	(dst)->f_blocks	= (src)->f_blocks;			\
62 	(dst)->f_bfree	= (src)->f_bfree;			\
63 	(dst)->f_bavail	= (src)->f_bavail;			\
64 	(dst)->f_files	= (src)->f_files;			\
65 	(dst)->f_ffree	= (src)->f_ffree;			\
66 	(dst)->f_favail	= (src)->f_favail;			\
67 	(dst)->f_fsid	= (src)->f_fsid;			\
68 	bcopy((src)->f_basetype, (dst)->f_basetype,		\
69 		sizeof ((dst)->f_basetype));			\
70 	(dst)->f_flag	= (src)->f_flag;			\
71 	(dst)->f_namemax = (src)->f_namemax;			\
72 	bcopy((src)->f_fstr, (dst)->f_fstr,			\
73 		sizeof ((dst)->f_fstr))
74 
75 /*
76  * Common routines for statvfs and fstatvfs.
77  */
78 
79 static int
80 cstatvfs32(struct vfs *vfsp, struct statvfs32 *ubp)
81 {
82 	struct statvfs64 ds64;
83 	struct statvfs32 ds32;
84 	int error;
85 
86 #if !defined(lint)
87 	ASSERT32(sizeof (struct statvfs) == sizeof (struct statvfs32));
88 	ASSERT32(sizeof (struct statvfs64) == sizeof (struct statvfs64_32));
89 #endif
90 
91 	bzero(&ds64, sizeof (ds64));
92 	if ((error = VFS_STATVFS(vfsp, &ds64)) != 0)
93 		return (error);
94 
95 	/*
96 	 * VFS_STATVFS can return data that is incompatible with the space
97 	 * available the 32-bit statvfs structure.  Check here to see if
98 	 * it will fit into the 32-bit structure, if not, return EOVERFLOW.
99 	 *
100 	 * The check for -1 is because some file systems return -1 in the
101 	 * fields that are irrelevant or nonessential, and we do not want
102 	 * to return EOVERFLOW for them.  For example: df is expected to
103 	 * show -1 in the output for some of these fields on NFS mounted
104 	 * filesystems.
105 	 */
106 	if (ds64.f_files == (fsfilcnt64_t)-1)
107 		ds64.f_files = UINT32_MAX;
108 	if (ds64.f_ffree == (fsfilcnt64_t)-1)
109 		ds64.f_ffree = UINT32_MAX;
110 	if (ds64.f_favail == (fsfilcnt64_t)-1)
111 		ds64.f_favail = UINT32_MAX;
112 	if (ds64.f_bavail == (fsblkcnt64_t)-1)
113 		ds64.f_bavail = UINT32_MAX;
114 	if (ds64.f_bfree == (fsblkcnt64_t)-1)
115 		ds64.f_bfree = UINT32_MAX;
116 
117 	if (ds64.f_blocks > UINT32_MAX || ds64.f_bfree > UINT32_MAX ||
118 	    ds64.f_bavail > UINT32_MAX || ds64.f_files > UINT32_MAX ||
119 	    ds64.f_ffree > UINT32_MAX || ds64.f_favail > UINT32_MAX)
120 		return (EOVERFLOW);
121 #ifdef _LP64
122 	/*
123 	 * On the 64-bit kernel, even these fields grow to 64-bit
124 	 * quantities in the statvfs64 structure.
125 	 */
126 	if (ds64.f_namemax == (ulong_t)-1l)
127 		ds64.f_namemax = UINT32_MAX;
128 
129 	if (ds64.f_bsize > UINT32_MAX || ds64.f_frsize > UINT32_MAX ||
130 	    ds64.f_fsid > UINT32_MAX || ds64.f_flag > UINT32_MAX ||
131 	    ds64.f_namemax > UINT32_MAX)
132 		return (EOVERFLOW);
133 #endif
134 
135 	bzero(&ds32, sizeof (ds32));
136 	STATVFSCOPY(&ds32, &ds64);
137 	if (copyout(&ds32, ubp, sizeof (ds32)) != 0)
138 		return (EFAULT);
139 	return (0);
140 }
141 
142 static int
143 cstatvfs64(struct vfs *vfsp, struct statvfs64 *ubp)
144 {
145 	struct statvfs64 ds64;
146 	int error;
147 
148 #if !defined(lint)
149 	ASSERT64(sizeof (struct statvfs) == sizeof (struct statvfs64));
150 #endif
151 	bzero(&ds64, sizeof (ds64));
152 	if ((error = VFS_STATVFS(vfsp, &ds64)) != 0)
153 		return (error);
154 	if (copyout(&ds64, ubp, sizeof (ds64)) != 0)
155 		return (EFAULT);
156 	return (0);
157 }
158 
159 /*
160  * Native system calls
161  */
162 int
163 statvfs(char *fname, struct statvfs *sbp)
164 {
165 	vnode_t *vp;
166 	int error;
167 
168 lookup:
169 	if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
170 		if (error == ESTALE)
171 			goto lookup;
172 		return (set_errno(error));
173 	}
174 #ifdef _LP64
175 	error = cstatvfs64(vp->v_vfsp, (struct statvfs64 *)sbp);
176 #else
177 	error = cstatvfs32(vp->v_vfsp, (struct statvfs32 *)sbp);
178 #endif
179 	VN_RELE(vp);
180 	if (error) {
181 		if (error == ESTALE)
182 			goto lookup;
183 		return (set_errno(error));
184 	}
185 	return (0);
186 }
187 
188 int
189 fstatvfs(int fdes, struct statvfs *sbp)
190 {
191 	struct file *fp;
192 	int error;
193 
194 	if ((fp = getf(fdes)) == NULL)
195 		return (set_errno(EBADF));
196 #ifdef _LP64
197 	error = cstatvfs64(fp->f_vnode->v_vfsp, (struct statvfs64 *)sbp);
198 #else
199 	error = cstatvfs32(fp->f_vnode->v_vfsp, (struct statvfs32 *)sbp);
200 #endif
201 	releasef(fdes);
202 	if (error)
203 		return (set_errno(error));
204 	return (0);
205 }
206 
207 #if defined(_ILP32)
208 
209 /*
210  * Large File system calls.
211  *
212  * (We deliberately don't have special "large file" system calls in the
213  * 64-bit kernel -- we just use the native versions, since they're just
214  * as functional.)
215  */
216 int
217 statvfs64(char *fname, struct statvfs64 *sbp)
218 {
219 	vnode_t *vp;
220 	int error;
221 
222 lookup:
223 	if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
224 		if (error == ESTALE)
225 			goto lookup;
226 		return (set_errno(error));
227 	}
228 	error = cstatvfs64(vp->v_vfsp, sbp);
229 	VN_RELE(vp);
230 	if (error) {
231 		if (error == ESTALE)
232 			goto lookup;
233 		return (set_errno(error));
234 	}
235 	return (0);
236 }
237 
238 int
239 fstatvfs64(int fdes, struct statvfs64 *sbp)
240 {
241 	struct file *fp;
242 	int error;
243 
244 	if ((fp = getf(fdes)) == NULL)
245 		return (set_errno(EBADF));
246 	error = cstatvfs64(fp->f_vnode->v_vfsp, sbp);
247 	releasef(fdes);
248 	if (error)
249 		return (set_errno(error));
250 	return (0);
251 }
252 
253 #endif	/* _ILP32 */
254 
255 #ifdef _SYSCALL32_IMPL
256 
257 static int
258 cstatvfs64_32(struct vfs *vfsp, struct statvfs64_32 *ubp)
259 {
260 	struct statvfs64 ds64;
261 	struct statvfs64_32 ds64_32;
262 	int error;
263 
264 	bzero(&ds64, sizeof (ds64));
265 	if ((error = VFS_STATVFS(vfsp, &ds64)) != 0)
266 		return (error);
267 
268 	/*
269 	 * On the 64-bit kernel, even these fields grow to 64-bit
270 	 * quantities in the statvfs64 structure.
271 	 */
272 	if (ds64.f_namemax == (ulong_t)-1l)
273 		ds64.f_namemax = UINT32_MAX;
274 
275 	if (ds64.f_bsize > UINT32_MAX || ds64.f_frsize > UINT32_MAX ||
276 	    ds64.f_fsid > UINT32_MAX || ds64.f_flag > UINT32_MAX ||
277 	    ds64.f_namemax > UINT32_MAX)
278 		return (EOVERFLOW);
279 
280 	STATVFSCOPY(&ds64_32, &ds64);
281 	if (copyout(&ds64_32, ubp, sizeof (ds64_32)) != 0)
282 		return (EFAULT);
283 	return (0);
284 }
285 
286 /*
287  * ILP32 "small file" system calls on LP64 kernel
288  */
289 int
290 statvfs32(char *fname, struct statvfs32 *sbp)
291 {
292 	vnode_t *vp;
293 	int error;
294 
295 lookup:
296 	if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
297 		if (error == ESTALE)
298 			goto lookup;
299 		return (set_errno(error));
300 	}
301 	error = cstatvfs32(vp->v_vfsp, sbp);
302 	VN_RELE(vp);
303 	if (error) {
304 		if (error == ESTALE)
305 			goto lookup;
306 		return (set_errno(error));
307 	}
308 	return (0);
309 }
310 
311 int
312 fstatvfs32(int fdes, struct statvfs32 *sbp)
313 {
314 	struct file *fp;
315 	int error;
316 
317 	if ((fp = getf(fdes)) == NULL)
318 		return (set_errno(EBADF));
319 	error = cstatvfs32(fp->f_vnode->v_vfsp, sbp);
320 	releasef(fdes);
321 	if (error)
322 		return (set_errno(error));
323 	return (0);
324 }
325 
326 /*
327  * ILP32 Large File system calls on LP64 kernel
328  */
329 int
330 statvfs64_32(char *fname, struct statvfs64_32 *sbp)
331 {
332 	vnode_t *vp;
333 	int error;
334 
335 lookup:
336 	if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
337 		if (error == ESTALE)
338 			goto lookup;
339 		return (set_errno(error));
340 	}
341 	error = cstatvfs64_32(vp->v_vfsp, sbp);
342 	VN_RELE(vp);
343 	if (error) {
344 		if (error == ESTALE)
345 			goto lookup;
346 		return (set_errno(error));
347 	}
348 	return (0);
349 }
350 
351 int
352 fstatvfs64_32(int fdes, struct statvfs64_32 *sbp)
353 {
354 	struct file *fp;
355 	int error;
356 
357 	if ((fp = getf(fdes)) == NULL)
358 		return (set_errno(EBADF));
359 	error = cstatvfs64_32(fp->f_vnode->v_vfsp, sbp);
360 	releasef(fdes);
361 	if (error)
362 		return (set_errno(error));
363 	return (0);
364 }
365 
366 #endif	/* _SYSCALL32_IMPL */
367