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