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