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