1 /* 2 * Copyright (c) 1980, 1990, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #ifndef lint 40 static const char copyright[] = 41 "@(#) Copyright (c) 1980, 1990, 1993, 1994\n\ 42 The Regents of the University of California. All rights reserved.\n"; 43 #endif /* not lint */ 44 45 #ifndef lint 46 #if 0 47 static char sccsid[] = "@(#)df.c 8.9 (Berkeley) 5/8/95"; 48 #else 49 static const char rcsid[] = 50 "$FreeBSD$"; 51 #endif 52 #endif /* not lint */ 53 54 #include <sys/param.h> 55 #include <sys/stat.h> 56 #include <sys/mount.h> 57 #include <ufs/ufs/ufsmount.h> 58 59 #include <err.h> 60 #include <errno.h> 61 #include <fcntl.h> 62 #include <math.h> 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <sysexits.h> 67 #include <unistd.h> 68 69 #define UNITS_SI 1 70 #define UNITS_2 2 71 72 #define KILO_SZ(n) (n) 73 #define MEGA_SZ(n) ((n) * (n)) 74 #define GIGA_SZ(n) ((n) * (n) * (n)) 75 #define TERA_SZ(n) ((n) * (n) * (n) * (n)) 76 #define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n)) 77 78 #define KILO_2_SZ (KILO_SZ(1024ULL)) 79 #define MEGA_2_SZ (MEGA_SZ(1024ULL)) 80 #define GIGA_2_SZ (GIGA_SZ(1024ULL)) 81 #define TERA_2_SZ (TERA_SZ(1024ULL)) 82 #define PETA_2_SZ (PETA_SZ(1024ULL)) 83 84 #define KILO_SI_SZ (KILO_SZ(1000ULL)) 85 #define MEGA_SI_SZ (MEGA_SZ(1000ULL)) 86 #define GIGA_SI_SZ (GIGA_SZ(1000ULL)) 87 #define TERA_SI_SZ (TERA_SZ(1000ULL)) 88 #define PETA_SI_SZ (PETA_SZ(1000ULL)) 89 90 unsigned long long vals_si [] = {1, KILO_SI_SZ, MEGA_SI_SZ, GIGA_SI_SZ, TERA_SI_SZ, PETA_SI_SZ}; 91 unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ}; 92 unsigned long long *valp; 93 94 typedef enum { NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX } unit_t; 95 96 int unitp [] = { NONE, KILO, MEGA, GIGA, TERA, PETA }; 97 98 int checkvfsname __P((const char *, char **)); 99 char **makevfslist __P((char *)); 100 long regetmntinfo __P((struct statfs **, long, char **)); 101 int bread __P((off_t, void *, int)); 102 char *getmntpt __P((char *)); 103 void prthuman __P((struct statfs *, long)); 104 void prthumanval __P((double)); 105 void prtstat __P((struct statfs *, int)); 106 int ufs_df __P((char *, int)); 107 unit_t unit_adjust __P((double *)); 108 void usage __P((void)); 109 110 int aflag = 0, hflag, iflag, nflag; 111 struct ufs_args mdev; 112 113 int 114 main(argc, argv) 115 int argc; 116 char *argv[]; 117 { 118 struct stat stbuf; 119 struct statfs statfsbuf, *mntbuf; 120 long mntsize; 121 int ch, err, i, maxwidth, rv, width; 122 char *mntpt, *mntpath, **vfslist; 123 124 vfslist = NULL; 125 while ((ch = getopt(argc, argv, "abgHhikmnPt:")) != -1) 126 switch (ch) { 127 case 'a': 128 aflag = 1; 129 break; 130 case 'b': 131 /* FALLTHROUGH */ 132 case 'P': 133 putenv("BLOCKSIZE=512"); 134 hflag = 0; 135 break; 136 case 'g': 137 putenv("BLOCKSIZE=1g"); 138 hflag = 0; 139 break; 140 case 'H': 141 hflag = UNITS_SI; 142 valp = vals_si; 143 break; 144 case 'h': 145 hflag = UNITS_2; 146 valp = vals_base2; 147 break; 148 case 'i': 149 iflag = 1; 150 break; 151 case 'k': 152 putenv("BLOCKSIZE=1k"); 153 hflag = 0; 154 break; 155 case 'm': 156 putenv("BLOCKSIZE=1m"); 157 hflag = 0; 158 break; 159 case 'n': 160 nflag = 1; 161 break; 162 case 't': 163 if (vfslist != NULL) 164 errx(1, "only one -t option may be specified."); 165 vfslist = makevfslist(optarg); 166 break; 167 case '?': 168 default: 169 usage(); 170 } 171 argc -= optind; 172 argv += optind; 173 174 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 175 maxwidth = 0; 176 for (i = 0; i < mntsize; i++) { 177 width = strlen(mntbuf[i].f_mntfromname); 178 if (width > maxwidth) 179 maxwidth = width; 180 } 181 182 rv = 0; 183 if (!*argv) { 184 mntsize = regetmntinfo(&mntbuf, mntsize, vfslist); 185 if (vfslist != NULL) { 186 maxwidth = 0; 187 for (i = 0; i < mntsize; i++) { 188 width = strlen(mntbuf[i].f_mntfromname); 189 if (width > maxwidth) 190 maxwidth = width; 191 } 192 } 193 for (i = 0; i < mntsize; i++) { 194 if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0) 195 prtstat(&mntbuf[i], maxwidth); 196 } 197 exit(rv); 198 } 199 200 for (; *argv; argv++) { 201 if (stat(*argv, &stbuf) < 0) { 202 err = errno; 203 if ((mntpt = getmntpt(*argv)) == 0) { 204 warn("%s", *argv); 205 rv = 1; 206 continue; 207 } 208 } else if ((stbuf.st_mode & S_IFMT) == S_IFCHR) { 209 rv = ufs_df(*argv, maxwidth) || rv; 210 continue; 211 } else if ((stbuf.st_mode & S_IFMT) == S_IFBLK) { 212 if ((mntpt = getmntpt(*argv)) == 0) { 213 mdev.fspec = *argv; 214 mntpath = strdup("/tmp/df.XXXXXX"); 215 if (mntpath == NULL) { 216 warn("strdup failed"); 217 rv = 1; 218 continue; 219 } 220 mntpt = mkdtemp(mntpath); 221 if (mntpt == NULL) { 222 warn("mkdtemp(\"%s\") failed", mntpath); 223 rv = 1; 224 free(mntpath); 225 continue; 226 } 227 if (mount("ufs", mntpt, MNT_RDONLY, 228 &mdev) != 0) { 229 rv = ufs_df(*argv, maxwidth) || rv; 230 (void)rmdir(mntpt); 231 free(mntpath); 232 continue; 233 } else if (statfs(mntpt, &statfsbuf) == 0) { 234 statfsbuf.f_mntonname[0] = '\0'; 235 prtstat(&statfsbuf, maxwidth); 236 } else { 237 warn("%s", *argv); 238 rv = 1; 239 } 240 (void)unmount(mntpt, 0); 241 (void)rmdir(mntpt); 242 free(mntpath); 243 continue; 244 } 245 } else 246 mntpt = *argv; 247 /* 248 * Statfs does not take a `wait' flag, so we cannot 249 * implement nflag here. 250 */ 251 if (statfs(mntpt, &statfsbuf) < 0) { 252 warn("%s", mntpt); 253 rv = 1; 254 continue; 255 } 256 if (argc == 1) 257 maxwidth = strlen(statfsbuf.f_mntfromname) + 1; 258 prtstat(&statfsbuf, maxwidth); 259 } 260 return (rv); 261 } 262 263 char * 264 getmntpt(name) 265 char *name; 266 { 267 long mntsize, i; 268 struct statfs *mntbuf; 269 270 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 271 for (i = 0; i < mntsize; i++) { 272 if (!strcmp(mntbuf[i].f_mntfromname, name)) 273 return (mntbuf[i].f_mntonname); 274 } 275 return (0); 276 } 277 278 /* 279 * Make a pass over the filesystem info in ``mntbuf'' filtering out 280 * filesystem types not in vfslist and possibly re-stating to get 281 * current (not cached) info. Returns the new count of valid statfs bufs. 282 */ 283 long 284 regetmntinfo(mntbufp, mntsize, vfslist) 285 struct statfs **mntbufp; 286 long mntsize; 287 char **vfslist; 288 { 289 int i, j; 290 struct statfs *mntbuf; 291 292 if (vfslist == NULL) 293 return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT)); 294 295 mntbuf = *mntbufp; 296 for (j = 0, i = 0; i < mntsize; i++) { 297 if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) 298 continue; 299 if (!nflag) 300 (void)statfs(mntbuf[i].f_mntonname,&mntbuf[j]); 301 else if (i != j) 302 mntbuf[j] = mntbuf[i]; 303 j++; 304 } 305 return (j); 306 } 307 308 /* 309 * Output in "human-readable" format. Uses 3 digits max and puts 310 * unit suffixes at the end. Makes output compact and easy to read, 311 * especially on huge disks. 312 * 313 */ 314 unit_t 315 unit_adjust(val) 316 double *val; 317 { 318 double abval; 319 unit_t unit; 320 unsigned int unit_sz; 321 322 abval = fabs(*val); 323 324 unit_sz = abval ? ilogb(abval) / 10 : 0; 325 326 if (unit_sz >= UNIT_MAX) { 327 unit = NONE; 328 } else { 329 unit = unitp[unit_sz]; 330 *val /= (double)valp[unit_sz]; 331 } 332 333 return (unit); 334 } 335 336 void 337 prthuman(sfsp, used) 338 struct statfs *sfsp; 339 long used; 340 { 341 342 prthumanval((double)sfsp->f_blocks * (double)sfsp->f_bsize); 343 prthumanval((double)used * (double)sfsp->f_bsize); 344 prthumanval((double)sfsp->f_bavail * (double)sfsp->f_bsize); 345 } 346 347 void 348 prthumanval(bytes) 349 double bytes; 350 { 351 352 unit_t unit; 353 unit = unit_adjust(&bytes); 354 355 if (bytes == 0) 356 (void)printf(" 0B"); 357 else if (bytes > 10) 358 (void)printf(" %5.0f%c", bytes, "BKMGTPE"[unit]); 359 else 360 (void)printf(" %5.1f%c", bytes, "BKMGTPE"[unit]); 361 } 362 363 /* 364 * Convert statfs returned filesystem size into BLOCKSIZE units. 365 * Attempts to avoid overflow for large filesystems. 366 */ 367 #define fsbtoblk(num, fsbs, bs) \ 368 (((fsbs) != 0 && (fsbs) < (bs)) ? \ 369 (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs))) 370 371 /* 372 * Print out status about a filesystem. 373 */ 374 void 375 prtstat(sfsp, maxwidth) 376 struct statfs *sfsp; 377 int maxwidth; 378 { 379 static long blocksize; 380 static int headerlen, timesthrough; 381 static char *header; 382 long used, availblks, inodes; 383 384 if (maxwidth < 11) 385 maxwidth = 11; 386 if (++timesthrough == 1) { 387 if (hflag) { 388 header = " Size"; 389 headerlen = strlen(header); 390 (void)printf("%-*.*s %-s Used Avail Capacity", 391 maxwidth, maxwidth, "Filesystem", header); 392 } else { 393 header = getbsize(&headerlen, &blocksize); 394 (void)printf("%-*.*s %-s Used Avail Capacity", 395 maxwidth, maxwidth, "Filesystem", header); 396 } 397 if (iflag) 398 (void)printf(" iused ifree %%iused"); 399 (void)printf(" Mounted on\n"); 400 } 401 (void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname); 402 used = sfsp->f_blocks - sfsp->f_bfree; 403 availblks = sfsp->f_bavail + used; 404 if (hflag) { 405 prthuman(sfsp, used); 406 } else { 407 (void)printf(" %*ld %8ld %8ld", headerlen, 408 fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize), 409 fsbtoblk(used, sfsp->f_bsize, blocksize), 410 fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize)); 411 } 412 (void)printf(" %5.0f%%", 413 availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0); 414 if (iflag) { 415 inodes = sfsp->f_files; 416 used = inodes - sfsp->f_ffree; 417 (void)printf(" %7ld %7ld %5.0f%% ", used, sfsp->f_ffree, 418 inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0); 419 } else 420 (void)printf(" "); 421 (void)printf(" %s\n", sfsp->f_mntonname); 422 } 423 424 /* 425 * This code constitutes the pre-system call Berkeley df code for extracting 426 * information from filesystem superblocks. 427 */ 428 #include <ufs/ufs/dinode.h> 429 #include <ufs/ffs/fs.h> 430 #include <errno.h> 431 #include <fstab.h> 432 433 union { 434 struct fs iu_fs; 435 char dummy[SBSIZE]; 436 } sb; 437 #define sblock sb.iu_fs 438 439 int rfd; 440 441 int 442 ufs_df(file, maxwidth) 443 char *file; 444 int maxwidth; 445 { 446 struct statfs statfsbuf; 447 struct statfs *sfsp; 448 char *mntpt; 449 static int synced; 450 451 if (synced++ == 0) 452 sync(); 453 454 if ((rfd = open(file, O_RDONLY)) < 0) { 455 warn("%s", file); 456 return (1); 457 } 458 if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) { 459 (void)close(rfd); 460 return (1); 461 } 462 sfsp = &statfsbuf; 463 sfsp->f_type = 1; 464 strcpy(sfsp->f_fstypename, "ufs"); 465 sfsp->f_flags = 0; 466 sfsp->f_bsize = sblock.fs_fsize; 467 sfsp->f_iosize = sblock.fs_bsize; 468 sfsp->f_blocks = sblock.fs_dsize; 469 sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag + 470 sblock.fs_cstotal.cs_nffree; 471 sfsp->f_bavail = freespace(&sblock, sblock.fs_minfree); 472 sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg; 473 sfsp->f_ffree = sblock.fs_cstotal.cs_nifree; 474 sfsp->f_fsid.val[0] = 0; 475 sfsp->f_fsid.val[1] = 0; 476 if ((mntpt = getmntpt(file)) == 0) 477 mntpt = ""; 478 memmove(&sfsp->f_mntonname[0], mntpt, MNAMELEN); 479 memmove(&sfsp->f_mntfromname[0], file, MNAMELEN); 480 prtstat(sfsp, maxwidth); 481 (void)close(rfd); 482 return (0); 483 } 484 485 int 486 bread(off, buf, cnt) 487 off_t off; 488 void *buf; 489 int cnt; 490 { 491 int nr; 492 493 (void)lseek(rfd, off, SEEK_SET); 494 if ((nr = read(rfd, buf, cnt)) != cnt) { 495 /* Probably a dismounted disk if errno == EIO. */ 496 if (errno != EIO) 497 (void)fprintf(stderr, "\ndf: %qd: %s\n", 498 off, strerror(nr > 0 ? EIO : errno)); 499 return (0); 500 } 501 return (1); 502 } 503 504 void 505 usage() 506 { 507 508 (void)fprintf(stderr, 509 "usage: df [-b | -H | -h | -k | -m | -P] [-ain] [-t type] [file | filesystem ...]\n"); 510 exit(EX_USAGE); 511 } 512