1 /*	$OpenBSD: df.c,v 1.43 2005/02/20 01:34:56 pedro Exp $	*/
2 /*	$NetBSD: df.c,v 1.21.2.1 1995/11/01 00:06:11 jtc Exp $	*/
3 
4 /*
5  * Copyright (c) 1980, 1990, 1993, 1994
6  *	The Regents of the University of California.  All rights reserved.
7  * (c) UNIX System Laboratories, Inc.
8  * All or some portions of this file are derived from material licensed
9  * to the University of California by American Telephone and Telegraph
10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11  * the permission of UNIX System Laboratories, Inc.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 #include <sys/mount.h>
41 
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <math.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <util.h>
51 
52 __IDSTRING(copyright, "@(#) Copyright (c) 1980, 1990, 1993, 1994\n\
53 	The Regents of the University of California.  All rights reserved.\n");
54 __SCCSID("@(#)df.c	8.7 (Berkeley) 4/2/94");
55 __RCSID("$MirOS: src/bin/df/df.c,v 1.4 2006/09/21 01:56:10 tg Exp $");
56 
57 extern	char *__progname;
58 
59 char	*getmntpt(char *);
60 int	 selected(const char *);
61 void	 maketypelist(char *);
62 long	 regetmntinfo(struct statfs **, long);
63 void	 bsdprint(struct statfs *, long, int);
64 void	 prtstat(struct statfs *, int, int, int);
65 void	 posixprint(struct statfs *, long, int);
66 int 	 bread(int, off_t, void *, int);
67 void	 usage(void);
68 
69 int		raw_df(char *, struct statfs *);
70 extern int	ffs_df(int, char *, struct statfs *);
71 extern int	e2fs_df(int, char *, struct statfs *);
72 
73 int	iflag, kflag, lflag, nflag, Pflag;
74 char	**typelist = NULL;
75 
76 int
main(int argc,char * argv[])77 main(int argc, char *argv[])
78 {
79 	struct stat stbuf;
80 	struct statfs *mntbuf;
81 	long mntsize;
82 	int ch, i;
83 	int width, maxwidth;
84 	char *mntpt;
85 
86 	while ((ch = getopt(argc, argv, "iklnPt:")) != -1)
87 		switch (ch) {
88 		case 'i':
89 			iflag = 1;
90 			break;
91 		case 'k':
92 			kflag = 1;
93 			break;
94 		case 'l':
95 			lflag = 1;
96 			break;
97 		case 'n':
98 			nflag = 1;
99 			break;
100 		case 'P':
101 			Pflag = 1;
102 			break;
103 		case 't':
104 			if (typelist != NULL)
105 				errx(1, "only one -t option may be specified.");
106 			maketypelist(optarg);
107 			break;
108 		default:
109 			usage();
110 		}
111 	argc -= optind;
112 	argv += optind;
113 
114 	if (iflag && Pflag) {
115 		warnx("-i is incompatible with -P");
116 		usage();
117 	}
118 
119 	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
120 	if (mntsize == 0)
121 		err(1, "retrieving information on mounted file systems");
122 
123 	if (!*argv) {
124 		mntsize = regetmntinfo(&mntbuf, mntsize);
125 	} else {
126 		mntbuf = calloc(argc, sizeof(struct statfs));
127 		mntsize = 0;
128 		for (; *argv; argv++) {
129 			if (stat(*argv, &stbuf) < 0) {
130 				if ((mntpt = getmntpt(*argv)) == 0) {
131 					warn("%s", *argv);
132 					continue;
133 				}
134 			} else if (S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode)) {
135 				if (!raw_df(*argv, &mntbuf[mntsize]))
136 					++mntsize;
137 				continue;
138 			} else
139 				mntpt = *argv;
140 			/*
141 			 * Statfs does not take a `wait' flag, so we cannot
142 			 * implement nflag here.
143 			 */
144 			if (!statfs(mntpt, &mntbuf[mntsize]))
145 				if (lflag && (mntbuf[mntsize].f_flags & MNT_LOCAL) == 0)
146 					warnx("%s is not a local file system",
147 					    *argv);
148 				else if (!selected(mntbuf[mntsize].f_fstypename))
149 					warnx("%s mounted as a %s file system",
150 					    *argv, mntbuf[mntsize].f_fstypename);
151 				else
152 					++mntsize;
153 			else
154 				warn("%s", *argv);
155 		}
156 	}
157 
158 	if (mntsize) {
159 		maxwidth = 0;
160 		for (i = 0; i < mntsize; i++) {
161 			width = strlen(mntbuf[i].f_mntfromname);
162 			if (width > maxwidth)
163 				maxwidth = width;
164 		}
165 
166 		if (maxwidth < 11)
167 			maxwidth = 11;
168 
169 		if (Pflag)
170 			posixprint(mntbuf, mntsize, maxwidth);
171 		else
172 			bsdprint(mntbuf, mntsize, maxwidth);
173 	}
174 
175 	exit(mntsize ? 0 : 1);
176 }
177 
178 char *
getmntpt(char * name)179 getmntpt(char *name)
180 {
181 	long mntsize, i;
182 	struct statfs *mntbuf;
183 
184 	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
185 	for (i = 0; i < mntsize; i++) {
186 		if (!strcmp(mntbuf[i].f_mntfromname, name))
187 			return (mntbuf[i].f_mntonname);
188 	}
189 	return (0);
190 }
191 
192 static enum { IN_LIST, NOT_IN_LIST } which;
193 
194 int
selected(const char * type)195 selected(const char *type)
196 {
197 	char **av;
198 
199 	/* If no type specified, it's always selected. */
200 	if (typelist == NULL)
201 		return (1);
202 	for (av = typelist; *av != NULL; ++av)
203 		if (!strncmp(type, *av, MFSNAMELEN))
204 			return (which == IN_LIST ? 1 : 0);
205 	return (which == IN_LIST ? 0 : 1);
206 }
207 
208 void
maketypelist(char * fslist)209 maketypelist(char *fslist)
210 {
211 	int i;
212 	char *nextcp, **av;
213 
214 	if ((fslist == NULL) || (fslist[0] == '\0'))
215 		errx(1, "empty type list");
216 
217 	/*
218 	 * XXX
219 	 * Note: the syntax is "noxxx,yyy" for no xxx's and
220 	 * no yyy's, not the more intuitive "noyyy,noyyy".
221 	 */
222 	if (fslist[0] == 'n' && fslist[1] == 'o') {
223 		fslist += 2;
224 		which = NOT_IN_LIST;
225 	} else
226 		which = IN_LIST;
227 
228 	/* Count the number of types. */
229 	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')) != NULL; i++)
230 		++nextcp;
231 
232 	/* Build an array of that many types. */
233 	if ((av = typelist = malloc((i + 1) * sizeof(char *))) == NULL)
234 		err(1, NULL);
235 	av[0] = fslist;
236 	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')) != NULL; i++) {
237 		*nextcp = '\0';
238 		av[i] = ++nextcp;
239 	}
240 	/* Terminate the array. */
241 	av[i] = NULL;
242 }
243 
244 /*
245  * Make a pass over the filesystem info in ``mntbuf'' filtering out
246  * filesystem types not in ``fsmask'' and possibly re-stating to get
247  * current (not cached) info.  Returns the new count of valid statfs bufs.
248  */
249 long
regetmntinfo(struct statfs ** mntbufp,long mntsize)250 regetmntinfo(struct statfs **mntbufp, long mntsize)
251 {
252 	int i, j;
253 	struct statfs *mntbuf;
254 
255 	if (!lflag && typelist == NULL)
256 		return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT));
257 
258 	mntbuf = *mntbufp;
259 	j = 0;
260 	for (i = 0; i < mntsize; i++) {
261 		if (lflag && (mntbuf[i].f_flags & MNT_LOCAL) == 0)
262 			continue;
263 		if (!selected(mntbuf[i].f_fstypename))
264 			continue;
265 		if (nflag)
266 			mntbuf[j] = mntbuf[i];
267 		else
268 			(void)statfs(mntbuf[i].f_mntonname, &mntbuf[j]);
269 		j++;
270 	}
271 	return (j);
272 }
273 
274 /*
275  * Convert statfs returned filesystem size into BLOCKSIZE units.
276  * Attempts to avoid overflow for large filesystems.
277  */
278 #define fsbtoblk(num, fsbs, bs) \
279 	(((fsbs) != 0 && (fsbs) < (bs)) ? \
280 		(num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs)))
281 
282 /*
283  * Print out status about a filesystem.
284  */
285 void
prtstat(struct statfs * sfsp,int maxwidth,int headerlen,int blocksize)286 prtstat(struct statfs *sfsp, int maxwidth, int headerlen, int blocksize)
287 {
288 	u_int32_t used, inodes;
289 	int64_t availblks;
290 
291 	(void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname);
292 	used = sfsp->f_blocks - sfsp->f_bfree;
293 	availblks = sfsp->f_bavail + used;
294 		(void)printf(" %*u %9u %9d", headerlen,
295 		    fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
296 		    fsbtoblk(used, sfsp->f_bsize, blocksize),
297 		    fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize));
298 	(void)printf(" %5.0f%%",
299 	    availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
300 	if (iflag) {
301 		inodes = sfsp->f_files;
302 		used = inodes - sfsp->f_ffree;
303 		(void)printf(" %7u %7u %5.0f%% ", used, sfsp->f_ffree,
304 		   inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
305 	} else
306 		(void)printf("  ");
307 	(void)printf("  %s\n", sfsp->f_mntonname);
308 }
309 
310 /*
311  * Print in traditional BSD format.
312  */
313 void
bsdprint(struct statfs * mntbuf,long mntsize,int maxwidth)314 bsdprint(struct statfs *mntbuf, long mntsize, int maxwidth)
315 {
316 	int i;
317 	char *header;
318 	int headerlen;
319 	long blocksize;
320 
321 	/* Print the header line */
322 		if (kflag) {
323 			blocksize = 1024;
324 			header = "1K-blocks";
325 			headerlen = strlen(header);
326 		} else
327 			header = getbsize(&headerlen, &blocksize);
328 		(void)printf("%-*.*s %s      Used     Avail Capacity",
329 			     maxwidth, maxwidth, "Filesystem", header);
330 	if (iflag)
331 		(void)printf(" iused   ifree  %%iused");
332 	(void)printf("  Mounted on\n");
333 
334 
335 	for (i = 0; i < mntsize; i++)
336 		prtstat(&mntbuf[i], maxwidth, headerlen, blocksize);
337 	return;
338 }
339 
340 /*
341  * Print in format defined by POSIX 1002.2, invoke with -P option.
342  */
343 void
posixprint(struct statfs * mntbuf,long mntsize,int maxwidth)344 posixprint(struct statfs *mntbuf, long mntsize, int maxwidth)
345 {
346 	int i;
347 	int blocksize;
348 	char *blockstr;
349 	struct statfs *sfsp;
350 	long used, avail;
351 	double percentused;
352 
353 	if (kflag) {
354 		blocksize = 1024;
355 		blockstr = "1024-blocks";
356 	} else {
357 		blocksize = 512;
358 		blockstr = " 512-blocks";
359 	}
360 
361 	(void)printf(
362 	    "%-*.*s %s       Used   Available Capacity Mounted on\n",
363 	    maxwidth, maxwidth, "Filesystem", blockstr);
364 
365 	for (i = 0; i < mntsize; i++) {
366 		sfsp = &mntbuf[i];
367 		used = sfsp->f_blocks - sfsp->f_bfree;
368 		avail = sfsp->f_bavail + used;
369 		if (avail == 0)
370 			percentused = 100.0;
371 		else
372 			percentused = (double)used / (double)avail * 100.0;
373 
374 		(void) printf ("%-*.*s %*d %10ld %11d %5.0f%%   %s\n",
375 			maxwidth, maxwidth, sfsp->f_mntfromname,
376 			(int)strlen(blockstr),
377 			fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
378 			fsbtoblk(used, sfsp->f_bsize, blocksize),
379 			fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize),
380 			percentused, sfsp->f_mntonname);
381 	}
382 }
383 
384 int
raw_df(char * file,struct statfs * sfsp)385 raw_df(char *file, struct statfs *sfsp)
386 {
387 	int rfd, ret = -1;
388 
389 	if ((rfd = open(file, O_RDONLY)) < 0) {
390 		warn("%s", file);
391 		return (-1);
392 	}
393 
394 	if (ffs_df(rfd, file, sfsp) == 0) {
395 		ret = 0;
396 	} else if (e2fs_df(rfd, file, sfsp) == 0) {
397 		ret = 0;
398 	}
399 
400 	close (rfd);
401 	return (ret);
402 }
403 
404 int
bread(int rfd,off_t off,void * buf,int cnt)405 bread(int rfd, off_t off, void *buf, int cnt)
406 {
407 	int nr;
408 
409 	(void)lseek(rfd, off, SEEK_SET);
410 	if ((nr = read(rfd, buf, cnt)) != cnt) {
411 		/* Probably a dismounted disk if errno == EIO. */
412 		if (errno != EIO)
413 			(void)fprintf(stderr, "\ndf: %qd: %s\n",
414 			    off, strerror(nr > 0 ? EIO : errno));
415 		return (0);
416 	}
417 	return (1);
418 }
419 
420 void
usage(void)421 usage(void)
422 {
423 	(void)fprintf(stderr,
424 	    "usage: %s [-iklnP] [-t type] [[file | file_system] ...]\n",
425 	    __progname);
426 	exit(1);
427 }
428