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 bread __P((off_t, void *, int)); 99 int checkvfsname __P((const char *, char **)); 100 char *getmntpt __P((char *)); 101 int main __P((int, char *[])); 102 char **makevfslist __P((char *)); 103 void prthuman __P((struct statfs *, long)); 104 void prthumanval __P((double)); 105 void prtstat __P((struct statfs *, int)); 106 long regetmntinfo __P((struct statfs **, long, char **)); 107 int ufs_df __P((char *, int)); 108 unit_t unit_adjust __P((double *)); 109 void usage __P((void)); 110 111 int aflag = 0, hflag, iflag, nflag; 112 struct ufs_args mdev; 113 114 int 115 main(argc, argv) 116 int argc; 117 char *argv[]; 118 { 119 struct stat stbuf; 120 struct statfs statfsbuf, *mntbuf; 121 const char *fstype; 122 char *mntpath, *mntpt, **vfslist; 123 long mntsize; 124 int ch, i, maxwidth, rv, width; 125 126 fstype = "ufs"; 127 128 vfslist = NULL; 129 while ((ch = getopt(argc, argv, "abgHhikmnPt:")) != -1) 130 switch (ch) { 131 case 'a': 132 aflag = 1; 133 break; 134 case 'b': 135 /* FALLTHROUGH */ 136 case 'P': 137 putenv("BLOCKSIZE=512"); 138 hflag = 0; 139 break; 140 case 'g': 141 putenv("BLOCKSIZE=1g"); 142 hflag = 0; 143 break; 144 case 'H': 145 hflag = UNITS_SI; 146 valp = vals_si; 147 break; 148 case 'h': 149 hflag = UNITS_2; 150 valp = vals_base2; 151 break; 152 case 'i': 153 iflag = 1; 154 break; 155 case 'k': 156 putenv("BLOCKSIZE=1k"); 157 hflag = 0; 158 break; 159 case 'm': 160 putenv("BLOCKSIZE=1m"); 161 hflag = 0; 162 break; 163 case 'n': 164 nflag = 1; 165 break; 166 case 't': 167 if (vfslist != NULL) 168 errx(1, "only one -t option may be specified."); 169 fstype = optarg; 170 vfslist = makevfslist(optarg); 171 break; 172 case '?': 173 default: 174 usage(); 175 } 176 argc -= optind; 177 argv += optind; 178 179 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 180 maxwidth = 0; 181 for (i = 0; i < mntsize; i++) { 182 width = strlen(mntbuf[i].f_mntfromname); 183 if (width > maxwidth) 184 maxwidth = width; 185 } 186 187 rv = 0; 188 if (!*argv) { 189 mntsize = regetmntinfo(&mntbuf, mntsize, vfslist); 190 if (vfslist != NULL) { 191 maxwidth = 0; 192 for (i = 0; i < mntsize; i++) { 193 width = strlen(mntbuf[i].f_mntfromname); 194 if (width > maxwidth) 195 maxwidth = width; 196 } 197 } 198 for (i = 0; i < mntsize; i++) { 199 if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0) 200 prtstat(&mntbuf[i], maxwidth); 201 } 202 exit(rv); 203 } 204 205 for (; *argv; argv++) { 206 if (stat(*argv, &stbuf) < 0) { 207 if ((mntpt = getmntpt(*argv)) == 0) { 208 warn("%s", *argv); 209 rv = 1; 210 continue; 211 } 212 } else if (S_ISCHR(stbuf.st_mode)) { 213 if ((mntpt = getmntpt(*argv)) == 0) { 214 mdev.fspec = *argv; 215 mntpath = strdup("/tmp/df.XXXXXX"); 216 if (mntpath == NULL) { 217 warn("strdup failed"); 218 rv = 1; 219 continue; 220 } 221 mntpt = mkdtemp(mntpath); 222 if (mntpt == NULL) { 223 warn("mkdtemp(\"%s\") failed", mntpath); 224 rv = 1; 225 free(mntpath); 226 continue; 227 } 228 if (mount(fstype, mntpt, MNT_RDONLY, 229 &mdev) != 0) { 230 rv = ufs_df(*argv, maxwidth) || rv; 231 (void)rmdir(mntpt); 232 free(mntpath); 233 continue; 234 } else if (statfs(mntpt, &statfsbuf) == 0) { 235 statfsbuf.f_mntonname[0] = '\0'; 236 prtstat(&statfsbuf, maxwidth); 237 } else { 238 warn("%s", *argv); 239 rv = 1; 240 } 241 (void)unmount(mntpt, 0); 242 (void)rmdir(mntpt); 243 free(mntpath); 244 continue; 245 } 246 } else 247 mntpt = *argv; 248 /* 249 * Statfs does not take a `wait' flag, so we cannot 250 * implement nflag here. 251 */ 252 if (statfs(mntpt, &statfsbuf) < 0) { 253 warn("%s", mntpt); 254 rv = 1; 255 continue; 256 } 257 if (argc == 1) 258 maxwidth = strlen(statfsbuf.f_mntfromname) + 1; 259 prtstat(&statfsbuf, maxwidth); 260 } 261 return (rv); 262 } 263 264 char * 265 getmntpt(name) 266 char *name; 267 { 268 long mntsize, i; 269 struct statfs *mntbuf; 270 271 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 272 for (i = 0; i < mntsize; i++) { 273 if (!strcmp(mntbuf[i].f_mntfromname, name)) 274 return (mntbuf[i].f_mntonname); 275 } 276 return (0); 277 } 278 279 /* 280 * Make a pass over the filesystem info in ``mntbuf'' filtering out 281 * filesystem types not in vfslist and possibly re-stating to get 282 * current (not cached) info. Returns the new count of valid statfs bufs. 283 */ 284 long 285 regetmntinfo(mntbufp, mntsize, vfslist) 286 struct statfs **mntbufp; 287 long mntsize; 288 char **vfslist; 289 { 290 int i, j; 291 struct statfs *mntbuf; 292 293 if (vfslist == NULL) 294 return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT)); 295 296 mntbuf = *mntbufp; 297 for (j = 0, i = 0; i < mntsize; i++) { 298 if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) 299 continue; 300 if (!nflag) 301 (void)statfs(mntbuf[i].f_mntonname,&mntbuf[j]); 302 else if (i != j) 303 mntbuf[j] = mntbuf[i]; 304 j++; 305 } 306 return (j); 307 } 308 309 /* 310 * Output in "human-readable" format. Uses 3 digits max and puts 311 * unit suffixes at the end. Makes output compact and easy to read, 312 * especially on huge disks. 313 * 314 */ 315 unit_t 316 unit_adjust(val) 317 double *val; 318 { 319 double abval; 320 unit_t unit; 321 unsigned int unit_sz; 322 323 abval = fabs(*val); 324 325 unit_sz = abval ? ilogb(abval) / 10 : 0; 326 327 if (unit_sz >= UNIT_MAX) { 328 unit = NONE; 329 } else { 330 unit = unitp[unit_sz]; 331 *val /= (double)valp[unit_sz]; 332 } 333 334 return (unit); 335 } 336 337 void 338 prthuman(sfsp, used) 339 struct statfs *sfsp; 340 long used; 341 { 342 343 prthumanval((double)sfsp->f_blocks * (double)sfsp->f_bsize); 344 prthumanval((double)used * (double)sfsp->f_bsize); 345 prthumanval((double)sfsp->f_bavail * (double)sfsp->f_bsize); 346 } 347 348 void 349 prthumanval(bytes) 350 double bytes; 351 { 352 353 unit_t unit; 354 unit = unit_adjust(&bytes); 355 356 if (bytes == 0) 357 (void)printf(" 0B"); 358 else if (bytes > 10) 359 (void)printf(" %5.0f%c", bytes, "BKMGTPE"[unit]); 360 else 361 (void)printf(" %5.1f%c", bytes, "BKMGTPE"[unit]); 362 } 363 364 /* 365 * Convert statfs returned filesystem size into BLOCKSIZE units. 366 * Attempts to avoid overflow for large filesystems. 367 */ 368 #define fsbtoblk(num, fsbs, bs) \ 369 (((fsbs) != 0 && (fsbs) < (bs)) ? \ 370 (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs))) 371 372 /* 373 * Print out status about a filesystem. 374 */ 375 void 376 prtstat(sfsp, maxwidth) 377 struct statfs *sfsp; 378 int maxwidth; 379 { 380 static long blocksize; 381 static int headerlen, timesthrough; 382 static const char *header; 383 long used, availblks, inodes; 384 385 if (maxwidth < 11) 386 maxwidth = 11; 387 if (++timesthrough == 1) { 388 if (hflag) { 389 header = " Size"; 390 headerlen = strlen(header); 391 (void)printf("%-*.*s %-s Used Avail Capacity", 392 maxwidth, maxwidth, "Filesystem", header); 393 } else { 394 header = getbsize(&headerlen, &blocksize); 395 (void)printf("%-*.*s %-s Used Avail Capacity", 396 maxwidth, maxwidth, "Filesystem", header); 397 } 398 if (iflag) 399 (void)printf(" iused ifree %%iused"); 400 (void)printf(" Mounted on\n"); 401 } 402 (void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname); 403 used = sfsp->f_blocks - sfsp->f_bfree; 404 availblks = sfsp->f_bavail + used; 405 if (hflag) { 406 prthuman(sfsp, used); 407 } else { 408 (void)printf(" %*ld %8ld %8ld", headerlen, 409 fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize), 410 fsbtoblk(used, sfsp->f_bsize, blocksize), 411 fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize)); 412 } 413 (void)printf(" %5.0f%%", 414 availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0); 415 if (iflag) { 416 inodes = sfsp->f_files; 417 used = inodes - sfsp->f_ffree; 418 (void)printf(" %7ld %7ld %5.0f%% ", used, sfsp->f_ffree, 419 inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0); 420 } else 421 (void)printf(" "); 422 (void)printf(" %s\n", sfsp->f_mntonname); 423 } 424 425 /* 426 * This code constitutes the pre-system call Berkeley df code for extracting 427 * information from filesystem superblocks. 428 */ 429 #include <ufs/ufs/dinode.h> 430 #include <ufs/ffs/fs.h> 431 #include <errno.h> 432 #include <fstab.h> 433 434 union { 435 struct fs iu_fs; 436 char dummy[SBSIZE]; 437 } sb; 438 #define sblock sb.iu_fs 439 440 int rfd; 441 442 int 443 ufs_df(file, maxwidth) 444 char *file; 445 int maxwidth; 446 { 447 struct statfs statfsbuf; 448 struct statfs *sfsp; 449 const char *mntpt; 450 static int synced; 451 452 if (synced++ == 0) 453 sync(); 454 455 if ((rfd = open(file, O_RDONLY)) < 0) { 456 warn("%s", file); 457 return (1); 458 } 459 if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) { 460 (void)close(rfd); 461 return (1); 462 } 463 sfsp = &statfsbuf; 464 sfsp->f_type = 1; 465 strcpy(sfsp->f_fstypename, "ufs"); 466 sfsp->f_flags = 0; 467 sfsp->f_bsize = sblock.fs_fsize; 468 sfsp->f_iosize = sblock.fs_bsize; 469 sfsp->f_blocks = sblock.fs_dsize; 470 sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag + 471 sblock.fs_cstotal.cs_nffree; 472 sfsp->f_bavail = freespace(&sblock, sblock.fs_minfree); 473 sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg; 474 sfsp->f_ffree = sblock.fs_cstotal.cs_nifree; 475 sfsp->f_fsid.val[0] = 0; 476 sfsp->f_fsid.val[1] = 0; 477 if ((mntpt = getmntpt(file)) == 0) 478 mntpt = ""; 479 memmove(&sfsp->f_mntonname[0], mntpt, (size_t)MNAMELEN); 480 memmove(&sfsp->f_mntfromname[0], file, (size_t)MNAMELEN); 481 prtstat(sfsp, maxwidth); 482 (void)close(rfd); 483 return (0); 484 } 485 486 int 487 bread(off, buf, cnt) 488 off_t off; 489 void *buf; 490 int cnt; 491 { 492 ssize_t nr; 493 494 (void)lseek(rfd, off, SEEK_SET); 495 if ((nr = read(rfd, buf, (size_t)cnt)) != (ssize_t)cnt) { 496 /* Probably a dismounted disk if errno == EIO. */ 497 if (errno != EIO) 498 (void)fprintf(stderr, "\ndf: %lld: %s\n", 499 (long long)off, strerror(nr > 0 ? EIO : errno)); 500 return (0); 501 } 502 return (1); 503 } 504 505 void 506 usage() 507 { 508 509 (void)fprintf(stderr, 510 "usage: df [-b | -H | -h | -k | -m | -P] [-ain] [-t type] [file | filesystem ...]\n"); 511 exit(EX_USAGE); 512 } 513