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