diff options
Diffstat (limited to 'lib/fsusage.c')
| -rw-r--r-- | lib/fsusage.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/lib/fsusage.c b/lib/fsusage.c new file mode 100644 index 00000000..5a864bf2 --- /dev/null +++ b/lib/fsusage.c | |||
| @@ -0,0 +1,281 @@ | |||
| 1 | /* fsusage.c -- return space usage of mounted filesystems | ||
| 2 | Copyright (C) 1991, 1992, 1996, 1998, 1999 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 Foundation, | ||
| 16 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
| 17 | |||
| 18 | #include "../plugins/config.h" | ||
| 19 | |||
| 20 | #if HAVE_INTTYPES_H | ||
| 21 | # include <inttypes.h> | ||
| 22 | #endif | ||
| 23 | #include <sys/types.h> | ||
| 24 | #include <sys/stat.h> | ||
| 25 | #include "fsusage.h" | ||
| 26 | |||
| 27 | #if HAVE_LIMITS_H | ||
| 28 | # include <limits.h> | ||
| 29 | #endif | ||
| 30 | #ifndef CHAR_BIT | ||
| 31 | # define CHAR_BIT 8 | ||
| 32 | #endif | ||
| 33 | |||
| 34 | int statfs (); | ||
| 35 | |||
| 36 | #if HAVE_SYS_PARAM_H | ||
| 37 | # include <sys/param.h> | ||
| 38 | #endif | ||
| 39 | |||
| 40 | #if HAVE_SYS_MOUNT_H | ||
| 41 | # include <sys/mount.h> | ||
| 42 | #endif | ||
| 43 | |||
| 44 | #if HAVE_SYS_VFS_H | ||
| 45 | # include <sys/vfs.h> | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #if HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */ | ||
| 49 | # include <sys/fs/s5param.h> | ||
| 50 | #endif | ||
| 51 | |||
| 52 | #if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY) | ||
| 53 | # include <sys/filsys.h> /* SVR2 */ | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #if HAVE_FCNTL_H | ||
| 57 | # include <fcntl.h> | ||
| 58 | #endif | ||
| 59 | |||
| 60 | #if HAVE_SYS_STATFS_H | ||
| 61 | # include <sys/statfs.h> | ||
| 62 | #endif | ||
| 63 | |||
| 64 | #if HAVE_DUSTAT_H /* AIX PS/2 */ | ||
| 65 | # include <sys/dustat.h> | ||
| 66 | #endif | ||
| 67 | |||
| 68 | #if HAVE_SYS_STATVFS_H /* SVR4 */ | ||
| 69 | # include <sys/statvfs.h> | ||
| 70 | int statvfs (); | ||
| 71 | #endif | ||
| 72 | |||
| 73 | /* Many space usage primitives use all 1 bits to denote a value that is | ||
| 74 | not applicable or unknown. Propagate this information by returning | ||
| 75 | a uintmax_t value that is all 1 bits if the argument is all 1 bits, | ||
| 76 | even if the argument is unsigned and smaller than uintmax_t. */ | ||
| 77 | #define PROPAGATE_ALL_ONES(x) ((x) == -1 ? (uintmax_t) -1 : (uintmax_t) (x)) | ||
| 78 | |||
| 79 | /* Extract the top bit of X as an uintmax_t value. */ | ||
| 80 | #define EXTRACT_TOP_BIT(x) ((x) \ | ||
| 81 | & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1))) | ||
| 82 | |||
| 83 | /* If a value is negative, many space usage primitives store it into an | ||
| 84 | integer variable by assignment, even if the variable's type is unsigned. | ||
| 85 | So, if a space usage variable X's top bit is set, convert X to the | ||
| 86 | uintmax_t value V such that (- (uintmax_t) V) is the negative of | ||
| 87 | the original value. If X's top bit is clear, just yield X. | ||
| 88 | Use PROPAGATE_TOP_BIT if the original value might be negative; | ||
| 89 | otherwise, use PROPAGATE_ALL_ONES. */ | ||
| 90 | #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1)) | ||
| 91 | |||
| 92 | int safe_read (); | ||
| 93 | |||
| 94 | /* Fill in the fields of FSP with information about space usage for | ||
| 95 | the filesystem on which PATH resides. | ||
| 96 | DISK is the device on which PATH is mounted, for space-getting | ||
| 97 | methods that need to know it. | ||
| 98 | Return 0 if successful, -1 if not. When returning -1, ensure that | ||
| 99 | ERRNO is either a system error value, or zero if DISK is NULL | ||
| 100 | on a system that requires a non-NULL value. */ | ||
| 101 | int | ||
| 102 | get_fs_usage (const char *path, const char *disk, struct fs_usage *fsp) | ||
| 103 | { | ||
| 104 | #ifdef STAT_STATFS3_OSF1 | ||
| 105 | |||
| 106 | struct statfs fsd; | ||
| 107 | |||
| 108 | if (statfs (path, &fsd, sizeof (struct statfs)) != 0) | ||
| 109 | return -1; | ||
| 110 | |||
| 111 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize); | ||
| 112 | |||
| 113 | #endif /* STAT_STATFS3_OSF1 */ | ||
| 114 | |||
| 115 | #ifdef STAT_STATFS2_FS_DATA /* Ultrix */ | ||
| 116 | |||
| 117 | struct fs_data fsd; | ||
| 118 | |||
| 119 | if (statfs (path, &fsd) != 1) | ||
| 120 | return -1; | ||
| 121 | |||
| 122 | fsp->fsu_blocksize = 1024; | ||
| 123 | fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot); | ||
| 124 | fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree); | ||
| 125 | fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen); | ||
| 126 | fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0; | ||
| 127 | fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot); | ||
| 128 | fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree); | ||
| 129 | |||
| 130 | #endif /* STAT_STATFS2_FS_DATA */ | ||
| 131 | |||
| 132 | #ifdef STAT_READ_FILSYS /* SVR2 */ | ||
| 133 | # ifndef SUPERBOFF | ||
| 134 | # define SUPERBOFF (SUPERB * 512) | ||
| 135 | # endif | ||
| 136 | |||
| 137 | struct filsys fsd; | ||
| 138 | int fd; | ||
| 139 | |||
| 140 | if (! disk) | ||
| 141 | { | ||
| 142 | errno = 0; | ||
| 143 | return -1; | ||
| 144 | } | ||
| 145 | |||
| 146 | fd = open (disk, O_RDONLY); | ||
| 147 | if (fd < 0) | ||
| 148 | return -1; | ||
| 149 | lseek (fd, (off_t) SUPERBOFF, 0); | ||
| 150 | if (safe_read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd) | ||
| 151 | { | ||
| 152 | close (fd); | ||
| 153 | return -1; | ||
| 154 | } | ||
| 155 | close (fd); | ||
| 156 | |||
| 157 | fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512); | ||
| 158 | fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize); | ||
| 159 | fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree); | ||
| 160 | fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree); | ||
| 161 | fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0; | ||
| 162 | fsp->fsu_files = (fsd.s_isize == -1 | ||
| 163 | ? (uintmax_t) -1 | ||
| 164 | : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1)); | ||
| 165 | fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode); | ||
| 166 | |||
| 167 | #endif /* STAT_READ_FILSYS */ | ||
| 168 | |||
| 169 | #ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */ | ||
| 170 | |||
| 171 | struct statfs fsd; | ||
| 172 | |||
| 173 | if (statfs (path, &fsd) < 0) | ||
| 174 | return -1; | ||
| 175 | |||
| 176 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize); | ||
| 177 | |||
| 178 | # ifdef STATFS_TRUNCATES_BLOCK_COUNTS | ||
| 179 | |||
| 180 | /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the | ||
| 181 | struct statfs are truncated to 2GB. These conditions detect that | ||
| 182 | truncation, presumably without botching the 4.1.1 case, in which | ||
| 183 | the values are not truncated. The correct counts are stored in | ||
| 184 | undocumented spare fields. */ | ||
| 185 | if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0) | ||
| 186 | { | ||
| 187 | fsd.f_blocks = fsd.f_spare[0]; | ||
| 188 | fsd.f_bfree = fsd.f_spare[1]; | ||
| 189 | fsd.f_bavail = fsd.f_spare[2]; | ||
| 190 | } | ||
| 191 | # endif /* STATFS_TRUNCATES_BLOCK_COUNTS */ | ||
| 192 | |||
| 193 | #endif /* STAT_STATFS2_BSIZE */ | ||
| 194 | |||
| 195 | #ifdef STAT_STATFS2_FSIZE /* 4.4BSD */ | ||
| 196 | |||
| 197 | struct statfs fsd; | ||
| 198 | |||
| 199 | if (statfs (path, &fsd) < 0) | ||
| 200 | return -1; | ||
| 201 | |||
| 202 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize); | ||
| 203 | |||
| 204 | #endif /* STAT_STATFS2_FSIZE */ | ||
| 205 | |||
| 206 | #ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */ | ||
| 207 | |||
| 208 | # if !_AIX && !defined _SEQUENT_ && !defined DOLPHIN | ||
| 209 | # define f_bavail f_bfree | ||
| 210 | # endif | ||
| 211 | |||
| 212 | struct statfs fsd; | ||
| 213 | |||
| 214 | if (statfs (path, &fsd, sizeof fsd, 0) < 0) | ||
| 215 | return -1; | ||
| 216 | |||
| 217 | /* Empirically, the block counts on most SVR3 and SVR3-derived | ||
| 218 | systems seem to always be in terms of 512-byte blocks, | ||
| 219 | no matter what value f_bsize has. */ | ||
| 220 | # if _AIX || defined(_CRAY) | ||
| 221 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize); | ||
| 222 | # else | ||
| 223 | fsp->fsu_blocksize = 512; | ||
| 224 | # endif | ||
| 225 | |||
| 226 | #endif /* STAT_STATFS4 */ | ||
| 227 | |||
| 228 | #ifdef STAT_STATVFS /* SVR4 */ | ||
| 229 | |||
| 230 | struct statvfs fsd; | ||
| 231 | |||
| 232 | if (statvfs (path, &fsd) < 0) | ||
| 233 | return -1; | ||
| 234 | |||
| 235 | /* f_frsize isn't guaranteed to be supported. */ | ||
| 236 | fsp->fsu_blocksize = | ||
| 237 | PROPAGATE_ALL_ONES (fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize); | ||
| 238 | |||
| 239 | #endif /* STAT_STATVFS */ | ||
| 240 | |||
| 241 | #if !defined(STAT_STATFS2_FS_DATA) && !defined(STAT_READ_FILSYS) | ||
| 242 | /* !Ultrix && !SVR2 */ | ||
| 243 | |||
| 244 | fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks); | ||
| 245 | fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree); | ||
| 246 | fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail); | ||
| 247 | fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0; | ||
| 248 | fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files); | ||
| 249 | fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree); | ||
| 250 | |||
| 251 | #endif /* not STAT_STATFS2_FS_DATA && not STAT_READ_FILSYS */ | ||
| 252 | |||
| 253 | return 0; | ||
| 254 | } | ||
| 255 | |||
| 256 | #if defined(_AIX) && defined(_I386) | ||
| 257 | /* AIX PS/2 does not supply statfs. */ | ||
| 258 | |||
| 259 | int | ||
| 260 | statfs (char *path, struct statfs *fsb) | ||
| 261 | { | ||
| 262 | struct stat stats; | ||
| 263 | struct dustat fsd; | ||
| 264 | |||
| 265 | if (stat (path, &stats)) | ||
| 266 | return -1; | ||
| 267 | if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd))) | ||
| 268 | return -1; | ||
| 269 | fsb->f_type = 0; | ||
| 270 | fsb->f_bsize = fsd.du_bsize; | ||
| 271 | fsb->f_blocks = fsd.du_fsize - fsd.du_isize; | ||
| 272 | fsb->f_bfree = fsd.du_tfree; | ||
| 273 | fsb->f_bavail = fsd.du_tfree; | ||
| 274 | fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb; | ||
| 275 | fsb->f_ffree = fsd.du_tinode; | ||
| 276 | fsb->f_fsid.val[0] = fsd.du_site; | ||
| 277 | fsb->f_fsid.val[1] = fsd.du_pckno; | ||
| 278 | return 0; | ||
| 279 | } | ||
| 280 | |||
| 281 | #endif /* _AIX && _I386 */ | ||
