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