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