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