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