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