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