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 * $Id$ 39 */ 40 41 #ifndef lint 42 static char copyright[] = 43 "@(#) Copyright (c) 1980, 1990, 1993, 1994\n\ 44 The Regents of the University of California. All rights reserved.\n"; 45 #endif /* not lint */ 46 47 #ifndef lint 48 static char sccsid[] = "@(#)df.c 8.7 (Berkeley) 4/2/94"; 49 #endif /* not lint */ 50 51 #include <sys/param.h> 52 #include <sys/stat.h> 53 #include <sys/mount.h> 54 55 #include <err.h> 56 #include <errno.h> 57 #include <fcntl.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <unistd.h> 62 63 /* XXX assumes MOUNT_MAXTYPE < 32 */ 64 #define MT(m) (1 << (m)) 65 66 /* fixed values */ 67 #define MT_NONE (0) 68 #define MT_ALL (MT(MOUNT_MAXTYPE+1)-1) 69 70 /* subject to change */ 71 #define MT_LOCAL \ 72 (MT(MOUNT_UFS)|MT(MOUNT_MFS)|MT(MOUNT_LFS)|MT(MOUNT_MSDOS)|MT(MOUNT_CD9660)) 73 #define MT_DEFAULT MT_ALL 74 75 struct typetab { 76 char *str; 77 long types; 78 } typetab[] = { 79 "ufs", MT(MOUNT_UFS), 80 "local", MT_LOCAL, 81 "all", MT_ALL, 82 "nfs", MT(MOUNT_NFS), 83 "mfs", MT(MOUNT_MFS), 84 "lfs", MT(MOUNT_LFS), 85 "msdos", MT(MOUNT_MSDOS), 86 "fdesc", MT(MOUNT_FDESC), 87 "portal", MT(MOUNT_PORTAL), 88 #if 0 89 /* return fsid of underlying FS */ 90 "lofs", MT(MOUNT_LOFS), 91 "null", MT(MOUNT_NULL), 92 "umap", MT(MOUNT_UMAP), 93 #endif 94 "kernfs", MT(MOUNT_KERNFS), 95 "procfs", MT(MOUNT_PROCFS), 96 "afs", MT(MOUNT_AFS), 97 "iso9660fs", MT(MOUNT_CD9660), 98 "cdfs", MT(MOUNT_CD9660), 99 "misc", MT(MOUNT_LOFS)|MT(MOUNT_FDESC)|MT(MOUNT_PORTAL)| 100 MT(MOUNT_KERNFS)|MT(MOUNT_PROCFS), 101 NULL, 0 102 }; 103 104 long addtype __P((long, char *)); 105 long regetmntinfo __P((struct statfs **, long, long)); 106 int bread __P((off_t, void *, int)); 107 char *getmntpt __P((char *)); 108 void prtstat __P((struct statfs *, int)); 109 void ufs_df __P((char *, int)); 110 void usage __P((void)); 111 112 int iflag, nflag, tflag; 113 struct ufs_args mdev; 114 115 int 116 main(argc, argv) 117 int argc; 118 char *argv[]; 119 { 120 struct stat stbuf; 121 struct statfs statfsbuf, *mntbuf; 122 long fsmask, mntsize; 123 int ch, err, i, maxwidth, width; 124 char *mntpt; 125 126 iflag = nflag = tflag = 0; 127 128 while ((ch = getopt(argc, argv, "iknt:")) != EOF) 129 switch (ch) { 130 case 'i': 131 iflag = 1; 132 break; 133 case 'k': 134 putenv("BLOCKSIZE=1k"); 135 break; 136 case 'n': 137 nflag = 1; 138 break; 139 case 't': 140 fsmask = addtype(fsmask, optarg); 141 tflag = 1; 142 break; 143 case '?': 144 default: 145 usage(); 146 } 147 argc -= optind; 148 argv += optind; 149 150 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 151 maxwidth = 0; 152 for (i = 0; i < mntsize; i++) { 153 width = strlen(mntbuf[i].f_mntfromname); 154 if (width > maxwidth) 155 maxwidth = width; 156 } 157 158 if (!*argv) { 159 if (!tflag) 160 fsmask = MT_DEFAULT; 161 mntsize = regetmntinfo(&mntbuf, mntsize, fsmask); 162 if (fsmask != MT_ALL) { 163 maxwidth = 0; 164 for (i = 0; i < mntsize; i++) { 165 width = strlen(mntbuf[i].f_mntfromname); 166 if (width > maxwidth) 167 maxwidth = width; 168 } 169 } 170 for (i = 0; i < mntsize; i++) 171 prtstat(&mntbuf[i], maxwidth); 172 exit(0); 173 } 174 175 for (; *argv; argv++) { 176 if (stat(*argv, &stbuf) < 0) { 177 err = errno; 178 if ((mntpt = getmntpt(*argv)) == 0) { 179 warn("%s", *argv); 180 continue; 181 } 182 } else if ((stbuf.st_mode & S_IFMT) == S_IFCHR) { 183 ufs_df(*argv, maxwidth); 184 continue; 185 } else if ((stbuf.st_mode & S_IFMT) == S_IFBLK) { 186 if ((mntpt = getmntpt(*argv)) == 0) { 187 mntpt = mktemp(strdup("/tmp/df.XXXXXX")); 188 mdev.fspec = *argv; 189 if (mkdir(mntpt, DEFFILEMODE) != 0) { 190 warn("%s", mntpt); 191 continue; 192 } 193 if (mount(MOUNT_UFS, mntpt, MNT_RDONLY, 194 &mdev) != 0) { 195 ufs_df(*argv, maxwidth); 196 (void)rmdir(mntpt); 197 continue; 198 } else if (statfs(mntpt, &statfsbuf)) { 199 statfsbuf.f_mntonname[0] = '\0'; 200 prtstat(&statfsbuf, maxwidth); 201 } else 202 warn("%s", *argv); 203 (void)unmount(mntpt, 0); 204 (void)rmdir(mntpt); 205 continue; 206 } 207 } else 208 mntpt = *argv; 209 /* 210 * Statfs does not take a `wait' flag, so we cannot 211 * implement nflag here. 212 */ 213 if (statfs(mntpt, &statfsbuf) < 0) { 214 warn("%s", mntpt); 215 continue; 216 } 217 if (argc == 1) 218 maxwidth = strlen(statfsbuf.f_mntfromname) + 1; 219 prtstat(&statfsbuf, maxwidth); 220 } 221 return (0); 222 } 223 224 char * 225 getmntpt(name) 226 char *name; 227 { 228 long mntsize, i; 229 struct statfs *mntbuf; 230 231 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 232 for (i = 0; i < mntsize; i++) { 233 if (!strcmp(mntbuf[i].f_mntfromname, name)) 234 return (mntbuf[i].f_mntonname); 235 } 236 return (0); 237 } 238 239 long 240 addtype(omask, str) 241 long omask; 242 char *str; 243 { 244 struct typetab *tp; 245 246 /* 247 * If it is one of our known types, add it to the current mask 248 */ 249 for (tp = typetab; tp->str; tp++) 250 if (strcmp(str, tp->str) == 0) 251 return (tp->types | (tflag ? omask : MT_NONE)); 252 /* 253 * See if it is the negation of one of the known values 254 */ 255 if (strlen(str) > 2 && str[0] == 'n' && str[1] == 'o') 256 for (tp = typetab; tp->str; tp++) 257 if (strcmp(str+2, tp->str) == 0) 258 return (~tp->types & (tflag ? omask : MT_ALL)); 259 errx(1, "unknown type `%s'", str); 260 } 261 262 /* 263 * Make a pass over the filesystem info in ``mntbuf'' filtering out 264 * filesystem types not in ``fsmask'' and possibly re-stating to get 265 * current (not cached) info. Returns the new count of valid statfs bufs. 266 */ 267 long 268 regetmntinfo(mntbufp, mntsize, fsmask) 269 struct statfs **mntbufp; 270 long mntsize, fsmask; 271 { 272 int i, j; 273 struct statfs *mntbuf; 274 275 if (fsmask == MT_ALL) 276 return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT)); 277 278 mntbuf = *mntbufp; 279 j = 0; 280 for (i = 0; i < mntsize; i++) { 281 if (fsmask & MT(mntbuf[i].f_type)) { 282 if (!nflag) 283 (void)statfs(mntbuf[i].f_mntonname,&mntbuf[j]); 284 else if (i != j) 285 mntbuf[j] = mntbuf[i]; 286 j++; 287 } 288 } 289 return (j); 290 } 291 292 /* 293 * Convert statfs returned filesystem size into BLOCKSIZE units. 294 * Attempts to avoid overflow for large filesystems. 295 */ 296 #define fsbtoblk(num, fsbs, bs) \ 297 (((fsbs) != 0 && (fsbs) < (bs)) ? \ 298 (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs))) 299 300 /* 301 * Print out status about a filesystem. 302 */ 303 void 304 prtstat(sfsp, maxwidth) 305 struct statfs *sfsp; 306 int maxwidth; 307 { 308 static long blocksize; 309 static int headerlen, timesthrough; 310 static char *header; 311 long used, availblks, inodes; 312 313 if (maxwidth < 11) 314 maxwidth = 11; 315 if (++timesthrough == 1) { 316 header = getbsize(&headerlen, &blocksize); 317 (void)printf("%-*.*s %s Used Avail Capacity", 318 maxwidth, maxwidth, "Filesystem", header); 319 if (iflag) 320 (void)printf(" iused ifree %%iused"); 321 (void)printf(" Mounted on\n"); 322 } 323 (void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname); 324 used = sfsp->f_blocks - sfsp->f_bfree; 325 availblks = sfsp->f_bavail + used; 326 (void)printf(" %*ld %8ld %8ld", headerlen, 327 fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize), 328 fsbtoblk(used, sfsp->f_bsize, blocksize), 329 fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize)); 330 (void)printf(" %5.0f%%", 331 availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0); 332 if (iflag) { 333 inodes = sfsp->f_files; 334 used = inodes - sfsp->f_ffree; 335 (void)printf(" %7ld %7ld %5.0f%% ", used, sfsp->f_ffree, 336 inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0); 337 } else 338 (void)printf(" "); 339 (void)printf(" %s\n", sfsp->f_mntonname); 340 } 341 342 /* 343 * This code constitutes the pre-system call Berkeley df code for extracting 344 * information from filesystem superblocks. 345 */ 346 #include <ufs/ffs/fs.h> 347 #include <errno.h> 348 #include <fstab.h> 349 350 union { 351 struct fs iu_fs; 352 char dummy[SBSIZE]; 353 } sb; 354 #define sblock sb.iu_fs 355 356 int rfd; 357 358 void 359 ufs_df(file, maxwidth) 360 char *file; 361 int maxwidth; 362 { 363 struct statfs statfsbuf; 364 struct statfs *sfsp; 365 char *mntpt; 366 static int synced; 367 368 if (synced++ == 0) 369 sync(); 370 371 if ((rfd = open(file, O_RDONLY)) < 0) { 372 warn("%s", file); 373 return; 374 } 375 if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) { 376 (void)close(rfd); 377 return; 378 } 379 sfsp = &statfsbuf; 380 sfsp->f_type = MOUNT_UFS; 381 sfsp->f_flags = 0; 382 sfsp->f_bsize = sblock.fs_fsize; 383 sfsp->f_iosize = sblock.fs_bsize; 384 sfsp->f_blocks = sblock.fs_dsize; 385 sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag + 386 sblock.fs_cstotal.cs_nffree; 387 sfsp->f_bavail = (sblock.fs_dsize * (100 - sblock.fs_minfree) / 100) - 388 (sblock.fs_dsize - sfsp->f_bfree); 389 if (sfsp->f_bavail < 0) 390 sfsp->f_bavail = 0; 391 sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg; 392 sfsp->f_ffree = sblock.fs_cstotal.cs_nifree; 393 sfsp->f_fsid.val[0] = 0; 394 sfsp->f_fsid.val[1] = 0; 395 if ((mntpt = getmntpt(file)) == 0) 396 mntpt = ""; 397 memmove(&sfsp->f_mntonname[0], mntpt, MNAMELEN); 398 memmove(&sfsp->f_mntfromname[0], file, MNAMELEN); 399 prtstat(sfsp, maxwidth); 400 (void)close(rfd); 401 } 402 403 int 404 bread(off, buf, cnt) 405 off_t off; 406 void *buf; 407 int cnt; 408 { 409 int nr; 410 411 (void)lseek(rfd, off, SEEK_SET); 412 if ((nr = read(rfd, buf, cnt)) != cnt) { 413 /* Probably a dismounted disk if errno == EIO. */ 414 if (errno != EIO) 415 (void)fprintf(stderr, "\ndf: %qd: %s\n", 416 off, strerror(nr > 0 ? EIO : errno)); 417 return (0); 418 } 419 return (1); 420 } 421 422 void 423 usage() 424 { 425 fprintf(stderr, 426 "usage: df [-ikn] [-t fstype] [file | file_system ...]\n"); 427 exit(1); 428 } 429