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.13 1997/02/22 14:02:57 peter Exp $ 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 #include <ufs/ufs/ufsmount.h> 55 56 #include <err.h> 57 #include <errno.h> 58 #include <fcntl.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 int checkvfsname __P((const char *, char **)); 65 char **makevfslist __P((char *)); 66 long regetmntinfo __P((struct statfs **, long, char **)); 67 int bread __P((off_t, void *, int)); 68 char *getmntpt __P((char *)); 69 void prtstat __P((struct statfs *, int)); 70 void ufs_df __P((char *, int)); 71 void usage __P((void)); 72 73 int iflag, nflag; 74 struct ufs_args mdev; 75 76 int 77 main(argc, argv) 78 int argc; 79 char *argv[]; 80 { 81 struct stat stbuf; 82 struct statfs statfsbuf, *mntbuf; 83 long mntsize; 84 int ch, err, i, maxwidth, width; 85 char *mntpt, **vfslist; 86 87 vfslist = NULL; 88 while ((ch = getopt(argc, argv, "iknt:")) != EOF) 89 switch (ch) { 90 case 'i': 91 iflag = 1; 92 break; 93 case 'k': 94 putenv("BLOCKSIZE=1k"); 95 break; 96 case 'n': 97 nflag = 1; 98 break; 99 case 't': 100 if (vfslist != NULL) 101 errx(1, "only one -t option may be specified."); 102 vfslist = makevfslist(optarg); 103 break; 104 case '?': 105 default: 106 usage(); 107 } 108 argc -= optind; 109 argv += optind; 110 111 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 112 maxwidth = 0; 113 for (i = 0; i < mntsize; i++) { 114 width = strlen(mntbuf[i].f_mntfromname); 115 if (width > maxwidth) 116 maxwidth = width; 117 } 118 119 if (!*argv) { 120 mntsize = regetmntinfo(&mntbuf, mntsize, vfslist); 121 if (vfslist != NULL) { 122 maxwidth = 0; 123 for (i = 0; i < mntsize; i++) { 124 width = strlen(mntbuf[i].f_mntfromname); 125 if (width > maxwidth) 126 maxwidth = width; 127 } 128 } 129 for (i = 0; i < mntsize; i++) 130 prtstat(&mntbuf[i], maxwidth); 131 exit(0); 132 } 133 134 for (; *argv; argv++) { 135 if (stat(*argv, &stbuf) < 0) { 136 err = errno; 137 if ((mntpt = getmntpt(*argv)) == 0) { 138 warn("%s", *argv); 139 continue; 140 } 141 } else if ((stbuf.st_mode & S_IFMT) == S_IFCHR) { 142 ufs_df(*argv, maxwidth); 143 continue; 144 } else if ((stbuf.st_mode & S_IFMT) == S_IFBLK) { 145 if ((mntpt = getmntpt(*argv)) == 0) { 146 mntpt = mktemp(strdup("/tmp/df.XXXXXX")); 147 mdev.fspec = *argv; 148 if (mkdir(mntpt, DEFFILEMODE) != 0) { 149 warn("%s", mntpt); 150 continue; 151 } 152 if (mount("ufs", mntpt, MNT_RDONLY, 153 &mdev) != 0) { 154 ufs_df(*argv, maxwidth); 155 (void)rmdir(mntpt); 156 continue; 157 } else if (statfs(mntpt, &statfsbuf) == 0) { 158 statfsbuf.f_mntonname[0] = '\0'; 159 prtstat(&statfsbuf, maxwidth); 160 } else 161 warn("%s", *argv); 162 (void)unmount(mntpt, 0); 163 (void)rmdir(mntpt); 164 continue; 165 } 166 } else 167 mntpt = *argv; 168 /* 169 * Statfs does not take a `wait' flag, so we cannot 170 * implement nflag here. 171 */ 172 if (statfs(mntpt, &statfsbuf) < 0) { 173 warn("%s", mntpt); 174 continue; 175 } 176 if (argc == 1) 177 maxwidth = strlen(statfsbuf.f_mntfromname) + 1; 178 prtstat(&statfsbuf, maxwidth); 179 } 180 return (0); 181 } 182 183 char * 184 getmntpt(name) 185 char *name; 186 { 187 long mntsize, i; 188 struct statfs *mntbuf; 189 190 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 191 for (i = 0; i < mntsize; i++) { 192 if (!strcmp(mntbuf[i].f_mntfromname, name)) 193 return (mntbuf[i].f_mntonname); 194 } 195 return (0); 196 } 197 198 /* 199 * Make a pass over the filesystem info in ``mntbuf'' filtering out 200 * filesystem types not in vfslist and possibly re-stating to get 201 * current (not cached) info. Returns the new count of valid statfs bufs. 202 */ 203 long 204 regetmntinfo(mntbufp, mntsize, vfslist) 205 struct statfs **mntbufp; 206 long mntsize; 207 char **vfslist; 208 { 209 int i, j; 210 struct statfs *mntbuf; 211 212 if (vfslist == NULL) 213 return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT)); 214 215 mntbuf = *mntbufp; 216 for (j = 0, i = 0; i < mntsize; i++) { 217 if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) 218 continue; 219 if (!nflag) 220 (void)statfs(mntbuf[i].f_mntonname,&mntbuf[j]); 221 else if (i != j) 222 mntbuf[j] = mntbuf[i]; 223 j++; 224 } 225 return (j); 226 } 227 228 /* 229 * Convert statfs returned filesystem size into BLOCKSIZE units. 230 * Attempts to avoid overflow for large filesystems. 231 */ 232 #define fsbtoblk(num, fsbs, bs) \ 233 (((fsbs) != 0 && (fsbs) < (bs)) ? \ 234 (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs))) 235 236 /* 237 * Print out status about a filesystem. 238 */ 239 void 240 prtstat(sfsp, maxwidth) 241 struct statfs *sfsp; 242 int maxwidth; 243 { 244 static long blocksize; 245 static int headerlen, timesthrough; 246 static char *header; 247 long used, availblks, inodes; 248 249 if (maxwidth < 11) 250 maxwidth = 11; 251 if (++timesthrough == 1) { 252 header = getbsize(&headerlen, &blocksize); 253 (void)printf("%-*.*s %s Used Avail Capacity", 254 maxwidth, maxwidth, "Filesystem", header); 255 if (iflag) 256 (void)printf(" iused ifree %%iused"); 257 (void)printf(" Mounted on\n"); 258 } 259 (void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname); 260 used = sfsp->f_blocks - sfsp->f_bfree; 261 availblks = sfsp->f_bavail + used; 262 (void)printf(" %*ld %8ld %8ld", headerlen, 263 fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize), 264 fsbtoblk(used, sfsp->f_bsize, blocksize), 265 fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize)); 266 (void)printf(" %5.0f%%", 267 availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0); 268 if (iflag) { 269 inodes = sfsp->f_files; 270 used = inodes - sfsp->f_ffree; 271 (void)printf(" %7ld %7ld %5.0f%% ", used, sfsp->f_ffree, 272 inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0); 273 } else 274 (void)printf(" "); 275 (void)printf(" %s\n", sfsp->f_mntonname); 276 } 277 278 /* 279 * This code constitutes the pre-system call Berkeley df code for extracting 280 * information from filesystem superblocks. 281 */ 282 #include <ufs/ufs/dinode.h> 283 #include <ufs/ffs/fs.h> 284 #include <errno.h> 285 #include <fstab.h> 286 287 union { 288 struct fs iu_fs; 289 char dummy[SBSIZE]; 290 } sb; 291 #define sblock sb.iu_fs 292 293 int rfd; 294 295 void 296 ufs_df(file, maxwidth) 297 char *file; 298 int maxwidth; 299 { 300 struct statfs statfsbuf; 301 struct statfs *sfsp; 302 char *mntpt; 303 static int synced; 304 305 if (synced++ == 0) 306 sync(); 307 308 if ((rfd = open(file, O_RDONLY)) < 0) { 309 warn("%s", file); 310 return; 311 } 312 if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) { 313 (void)close(rfd); 314 return; 315 } 316 sfsp = &statfsbuf; 317 sfsp->f_type = 1; 318 strcpy(sfsp->f_fstypename, "ufs"); 319 sfsp->f_flags = 0; 320 sfsp->f_bsize = sblock.fs_fsize; 321 sfsp->f_iosize = sblock.fs_bsize; 322 sfsp->f_blocks = sblock.fs_dsize; 323 sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag + 324 sblock.fs_cstotal.cs_nffree; 325 sfsp->f_bavail = freespace(&sblock, sblock.fs_minfree); 326 sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg; 327 sfsp->f_ffree = sblock.fs_cstotal.cs_nifree; 328 sfsp->f_fsid.val[0] = 0; 329 sfsp->f_fsid.val[1] = 0; 330 if ((mntpt = getmntpt(file)) == 0) 331 mntpt = ""; 332 memmove(&sfsp->f_mntonname[0], mntpt, MNAMELEN); 333 memmove(&sfsp->f_mntfromname[0], file, MNAMELEN); 334 prtstat(sfsp, maxwidth); 335 (void)close(rfd); 336 } 337 338 int 339 bread(off, buf, cnt) 340 off_t off; 341 void *buf; 342 int cnt; 343 { 344 int nr; 345 346 (void)lseek(rfd, off, SEEK_SET); 347 if ((nr = read(rfd, buf, cnt)) != cnt) { 348 /* Probably a dismounted disk if errno == EIO. */ 349 if (errno != EIO) 350 (void)fprintf(stderr, "\ndf: %qd: %s\n", 351 off, strerror(nr > 0 ? EIO : errno)); 352 return (0); 353 } 354 return (1); 355 } 356 357 void 358 usage() 359 { 360 (void)fprintf(stderr, 361 "usage: df [-ikn] [-t type] [file | filesystem ...]\n"); 362 exit(1); 363 } 364