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