1/* fsusage.c -- return space usage of mounted filesystems 2 Copyright (C) 1991, 1992 Free Software Foundation, Inc. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2, or (at your option) 7 any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software 16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 17 18 This file was modified slightly by Ian Lance Taylor, December 1992, 19 and again July 1995, for use with Taylor UUCP. */ 20 21#include "uucp.h" 22#include "uudefs.h" 23#include "sysdep.h" 24#include "fsusg.h" 25 26int statfs (); 27 28#if HAVE_SYS_PARAM_H 29#include <sys/param.h> 30#endif 31 32#if HAVE_SYS_MOUNT_H 33#include <sys/mount.h> 34#endif 35 36#if HAVE_SYS_VFS_H 37#include <sys/vfs.h> 38#endif 39 40#if HAVE_SYS_FILSYS_H 41#include <sys/filsys.h> /* SVR2. */ 42#endif 43 44#if HAVE_FCNTL_H 45#include <fcntl.h> 46#endif 47 48#if HAVE_SYS_STATFS_H 49#include <sys/statfs.h> 50#endif 51 52#if HAVE_SYS_DUSTAT_H /* AIX PS/2. */ 53#include <sys/dustat.h> 54#endif 55 56#if HAVE_SYS_STATVFS_H /* SVR4. */ 57#include <sys/statvfs.h> 58int statvfs (); 59#endif 60 61#if HAVE_USTAT_H /* SVR2 and others. */ 62#include <ustat.h> 63#endif 64 65#if STAT_DISK_SPACE /* QNX. */ 66#include <sys/disk.h> 67#include <errno.h> 68#endif 69 70#define STAT_NONE 0 71 72#if ! STAT_STATFS3_OSF1 73#if ! STAT_STATFS2_FS_DATA 74#if ! STAT_STATFS2_BSIZE 75#if ! STAT_STATFS2_FSIZE 76#if ! STAT_STATFS4 77#if ! STAT_STATVFS 78#if ! STAT_DISK_SPACE 79#if ! STAT_USTAT 80#undef STAT_NONE 81#define STAT_NONE 1 82#endif 83#endif 84#endif 85#endif 86#endif 87#endif 88#endif 89#endif 90 91#if ! STAT_NONE 92 93static long adjust_blocks P((long blocks, int fromsize, int tosize)); 94 95/* Return the number of TOSIZE-byte blocks used by 96 BLOCKS FROMSIZE-byte blocks, rounding away from zero. 97 TOSIZE must be positive. Return -1 if FROMSIZE is not positive. */ 98 99static long 100adjust_blocks (blocks, fromsize, tosize) 101 long blocks; 102 int fromsize, tosize; 103{ 104 if (tosize <= 0) 105 abort (); 106 if (fromsize <= 0) 107 return -1; 108 109 if (fromsize == tosize) /* E.g., from 512 to 512. */ 110 return blocks; 111 else if (fromsize > tosize) /* E.g., from 2048 to 512. */ 112 return blocks * (fromsize / tosize); 113 else /* E.g., from 256 to 512. */ 114 return (blocks + (blocks < 0 ? -1 : 1)) / (tosize / fromsize); 115} 116 117#endif 118 119/* Fill in the fields of FSP with information about space usage for 120 the filesystem on which PATH resides. 121 DISK is the device on which PATH is mounted, for space-getting 122 methods that need to know it. 123 Return 0 if successful, -1 if not. */ 124 125int 126get_fs_usage (path, disk, fsp) 127 char *path, *disk ATTRIBUTE_UNUSED; 128 struct fs_usage *fsp; 129{ 130#if STAT_NONE 131 return -1; 132#endif 133 134#if STAT_STATFS3_OSF1 135 struct statfs fsd; 136 137 if (statfs (path, &fsd, sizeof (struct statfs)) != 0) 138 return -1; 139#define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_fsize, 512) 140#endif /* STAT_STATFS3_OSF1 */ 141 142#if STAT_STATFS2_FS_DATA /* Ultrix. */ 143 struct fs_data fsd; 144 145 if (statfs (path, &fsd) != 1) 146 return -1; 147#define CONVERT_BLOCKS(b) adjust_blocks ((long) (b), 1024, 512) 148 fsp->fsu_blocks = CONVERT_BLOCKS (fsd.fd_req.btot); 149 fsp->fsu_bfree = CONVERT_BLOCKS (fsd.fd_req.bfree); 150 fsp->fsu_bavail = CONVERT_BLOCKS (fsd.fd_req.bfreen); 151 fsp->fsu_files = fsd.fd_req.gtot; 152 fsp->fsu_ffree = fsd.fd_req.gfree; 153#endif 154 155#if STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX. */ 156 struct statfs fsd; 157 158 if (statfs (path, &fsd) < 0) 159 return -1; 160#define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_bsize, 512) 161#endif 162 163#if STAT_STATFS2_FSIZE /* 4.4BSD. */ 164 struct statfs fsd; 165 166 if (statfs (path, &fsd) < 0) 167 return -1; 168#define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_fsize, 512) 169#endif 170 171#if STAT_STATFS4 /* SVR3, Dynix, Irix. */ 172 struct statfs fsd; 173 174 if (statfs (path, &fsd, sizeof fsd, 0) < 0) 175 return -1; 176 /* Empirically, the block counts on most SVR3 and SVR3-derived 177 systems seem to always be in terms of 512-byte blocks, 178 no matter what value f_bsize has. */ 179# if _AIX 180# define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_bsize, 512) 181# else 182# define CONVERT_BLOCKS(b) (b) 183# ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx. */ 184# ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */ 185# define f_bavail f_bfree 186# endif 187# endif 188# endif 189#endif 190 191#if STAT_STATVFS /* SVR4. */ 192 struct statvfs fsd; 193 194 if (statvfs (path, &fsd) < 0) 195 return -1; 196 /* f_frsize isn't guaranteed to be supported. */ 197#define CONVERT_BLOCKS(b) \ 198 adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512) 199#endif 200 201#if STAT_DISK_SPACE /* QNX. */ 202 int o; 203 int iret; 204 long cfree_blocks, ctotal_blocks; 205 char *zpath; 206 char *zslash; 207 208 zpath = zbufcpy (path); 209 while ((o = open (zpath, O_RDONLY, 0)) == -1 210 && errno == ENOENT) 211 { 212 /* The named file doesn't exist, so we can't open it. Try the 213 directory containing it. */ 214 if ((strcmp ("/", zpath) == 0) 215 || (strcmp (zpath, ".") == 0) 216 || (strcmp (zpath, "") == 0) 217 /* QNX peculiarity: "//2" means root on node 2 */ 218 || ((strncmp (zpath, "//", 2) == 0) 219 && (strchr (zpath + 2, '/') == NULL))) 220 { 221 /* We can't shorten this! */ 222 break; 223 } 224 225 /* Shorten the pathname by one component and try again. */ 226 zslash = strrchr (zpath, '/'); 227 if (zslash == NULL) 228 { 229 /* Try the current directory. We can open directories. */ 230 zpath[0] = '.'; 231 zpath[1] = '\0'; 232 } 233 else if (zslash == zpath) 234 { 235 /* Try the root directory. */ 236 zpath[0] = '/'; 237 zpath[1] = '\0'; 238 } 239 else 240 { 241 /* Chop off last path component. */ 242 zslash[0] = '\0'; 243 } 244 } 245 if (o == -1) 246 { 247 ulog (LOG_ERROR, "get_fs_usage: open (%s) failed: %s", zpath, 248 strerror (errno)); 249 ubuffree (zpath); 250 return -1; 251 } 252 ubuffree (zpath); 253 254 iret = disk_space (o, &cfree_blocks, &ctotal_blocks); 255 (void) close (o); 256 if (iret == -1) 257 { 258 ulog (LOG_ERROR, "get_fs_usage: disk_space failed: %s", 259 strerror (errno)); 260 return -1; 261 } 262 263 fsp->fsu_blocks = ctotal_blocks; 264 fsp->fsu_bfree = cfree_blocks; 265 fsp->fsu_bavail = cfree_blocks; 266 267 /* QNX has no limit on the number of inodes. Most inodes are stored 268 directly in the directory entry. */ 269 fsp->fsu_files = -1; 270 fsp->fsu_ffree = -1; 271#endif /* STAT_DISK_SPACE */ 272 273#if STAT_USTAT 274 struct stat sstat; 275 struct ustat s; 276 277 if (stat (path, &sstat) < 0 278 || ustat (sstat.st_dev, &s) < 0) 279 return -1; 280 fsp->fsu_blocks = -1; 281 fsp->fsu_bfree = s.f_tfree; 282 fsp->fsu_bavail = s.f_tfree; 283 fsp->fsu_files = -1; 284 fsp->fsu_ffree = -1; 285#endif 286 287#if ! STAT_STATFS2_FS_DATA /* ! Ultrix */ 288#if ! STAT_DISK_SPACE 289#if ! STAT_USTAT 290#if ! STAT_NONE 291 fsp->fsu_blocks = CONVERT_BLOCKS (fsd.f_blocks); 292 fsp->fsu_bfree = CONVERT_BLOCKS (fsd.f_bfree); 293 fsp->fsu_bavail = CONVERT_BLOCKS (fsd.f_bavail); 294 fsp->fsu_files = fsd.f_files; 295 fsp->fsu_ffree = fsd.f_ffree; 296#endif 297#endif 298#endif 299#endif 300 301 return 0; 302} 303 304#ifdef _AIX 305#ifdef _I386 306/* AIX PS/2 does not supply statfs. */ 307 308int 309statfs (path, fsb) 310 char *path; 311 struct statfs *fsb; 312{ 313 struct stat stats; 314 struct dustat fsd; 315 316 if (stat (path, &stats)) 317 return -1; 318 if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd))) 319 return -1; 320 fsb->f_type = 0; 321 fsb->f_bsize = fsd.du_bsize; 322 fsb->f_blocks = fsd.du_fsize - fsd.du_isize; 323 fsb->f_bfree = fsd.du_tfree; 324 fsb->f_bavail = fsd.du_tfree; 325 fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb; 326 fsb->f_ffree = fsd.du_tinode; 327 fsb->f_fsid.val[0] = fsd.du_site; 328 fsb->f_fsid.val[1] = fsd.du_pckno; 329 return 0; 330} 331#endif /* _I386 */ 332#endif /* _AIX */ 333