xref: /freebsd/bin/df/df.c (revision df7f5d4de4592a8948a25ce01e5bddfbb7ce39dc)
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