GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/df/df.c Lines: 124 189 65.6 %
Date: 2017-11-07 Branches: 70 148 47.3 %

Line Branch Exec Source
1
/*	$OpenBSD: df.c,v 1.59 2016/08/14 21:07:40 krw 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/stat.h>
39
#include <sys/mount.h>
40
41
#include <err.h>
42
#include <errno.h>
43
#include <fcntl.h>
44
#include <stdio.h>
45
#include <stdlib.h>
46
#include <string.h>
47
#include <unistd.h>
48
#include <util.h>
49
50
int		 bread(int, off_t, void *, int);
51
static void	 bsdprint(struct statfs *, long, int);
52
char		*getmntpt(char *);
53
static void	 maketypelist(char *);
54
static void	 posixprint(struct statfs *, long, int);
55
static void	 prthuman(struct statfs *sfsp, unsigned long long);
56
static void	 prthumanval(long long);
57
static void	 prtstat(struct statfs *, int, int, int);
58
static long	 regetmntinfo(struct statfs **, long);
59
static int	 selected(const char *);
60
static __dead void usage(void);
61
62
extern int	 e2fs_df(int, char *, struct statfs *);
63
extern int	 ffs_df(int, char *, struct statfs *);
64
static int	 raw_df(char *, struct statfs *);
65
66
int	hflag, iflag, kflag, lflag, nflag, Pflag;
67
char	**typelist = NULL;
68
69
int
70
main(int argc, char *argv[])
71
{
72
246
	struct stat stbuf;
73
123
	struct statfs *mntbuf;
74
	long mntsize;
75
	int ch, i;
76
	int width, maxwidth;
77
	char *mntpt;
78
79
123
	if (pledge("stdio rpath flock cpath wpath", NULL) == -1)
80
		err(1, "pledge");
81
82
241
	while ((ch = getopt(argc, argv, "hiklnPt:")) != -1)
83


118
		switch (ch) {
84
		case 'h':
85
9
			hflag = 1;
86
9
			kflag = 0;
87
9
			break;
88
		case 'i':
89
1
			iflag = 1;
90
1
			break;
91
		case 'k':
92
1
			kflag = 1;
93
1
			hflag = 0;
94
1
			break;
95
		case 'l':
96
2
			lflag = 1;
97
2
			break;
98
		case 'n':
99
1
			nflag = 1;
100
1
			break;
101
		case 'P':
102
104
			Pflag = 1;
103
104
			break;
104
		case 't':
105
			if (typelist != NULL)
106
				errx(1, "only one -t option may be specified.");
107
			maketypelist(optarg);
108
			break;
109
		default:
110
			usage();
111
		}
112
123
	argc -= optind;
113
123
	argv += optind;
114
115
123
	if ((iflag || hflag) && Pflag) {
116
		warnx("-h and -i are incompatible with -P");
117
		usage();
118
	}
119
120
123
	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
121
123
	if (mntsize == 0)
122
		err(1, "retrieving information on mounted file systems");
123
124
123
	if (!*argv) {
125
11
		mntsize = regetmntinfo(&mntbuf, mntsize);
126
11
	} else {
127
112
		mntbuf = calloc(argc, sizeof(struct statfs));
128
112
		if (mntbuf == NULL)
129
			err(1, NULL);
130
		mntsize = 0;
131
448
		for (; *argv; argv++) {
132
112
			if (stat(*argv, &stbuf) < 0) {
133
				if ((mntpt = getmntpt(*argv)) == 0) {
134
					warn("%s", *argv);
135
					continue;
136
				}
137

224
			} else if (S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode)) {
138
				if (!raw_df(*argv, &mntbuf[mntsize]))
139
					++mntsize;
140
				continue;
141
			} else
142
112
				mntpt = *argv;
143
			/*
144
			 * Statfs does not take a `wait' flag, so we cannot
145
			 * implement nflag here.
146
			 */
147
112
			if (!statfs(mntpt, &mntbuf[mntsize]))
148

112
				if (lflag && (mntbuf[mntsize].f_flags & MNT_LOCAL) == 0)
149
					warnx("%s is not a local file system",
150
					    *argv);
151
112
				else if (!selected(mntbuf[mntsize].f_fstypename))
152
					warnx("%s mounted as a %s file system",
153
					    *argv, mntbuf[mntsize].f_fstypename);
154
				else
155
112
					++mntsize;
156
			else
157
				warn("%s", *argv);
158
		}
159
	}
160
161
123
	if (mntsize) {
162
		maxwidth = 11;
163
668
		for (i = 0; i < mntsize; i++) {
164
211
			width = strlen(mntbuf[i].f_mntfromname);
165
211
			if (width > maxwidth)
166
				maxwidth = width;
167
		}
168
169
123
		if (Pflag)
170
104
			posixprint(mntbuf, mntsize, maxwidth);
171
		else
172
19
			bsdprint(mntbuf, mntsize, maxwidth);
173
	}
174
175
246
	return (mntsize ? 0 : 1);
176
123
}
177
178
char *
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
static int
195
selected(const char *type)
196
{
197
	char **av;
198
199
	/* If no type specified, it's always selected. */
200
260
	if (typelist == NULL)
201
130
		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
130
}
207
208
static void
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 = calloc(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
static long
250
regetmntinfo(struct statfs **mntbufp, long mntsize)
251
{
252
	int i, j;
253
	struct statfs *mntbuf;
254
255
22
	if (!lflag && typelist == NULL)
256
27
		return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT));
257
258
2
	mntbuf = *mntbufp;
259
	j = 0;
260
40
	for (i = 0; i < mntsize; i++) {
261

36
		if (lflag && (mntbuf[i].f_flags & MNT_LOCAL) == 0)
262
			continue;
263
18
		if (!selected(mntbuf[i].f_fstypename))
264
			continue;
265
18
		if (nflag)
266
9
			mntbuf[j] = mntbuf[i];
267
		else
268
9
			(void)statfs(mntbuf[i].f_mntonname, &mntbuf[j]);
269
18
		j++;
270
18
	}
271
2
	return (j);
272
11
}
273
274
/*
275
 * "human-readable" output: use 3 digits max.--put unit suffixes at
276
 * the end.  Makes output compact and easy-to-read esp. on huge disks.
277
 * Code moved into libutil; this is now just a wrapper.
278
 */
279
static void
280
prthumanval(long long bytes)
281
{
282
486
	char ret[FMT_SCALED_STRSIZE];
283
284
243
	if (fmt_scaled(bytes, ret) == -1) {
285
		(void)printf(" %lld", bytes);
286
		return;
287
	}
288
243
	(void)printf(" %7s", ret);
289
486
}
290
291
static void
292
prthuman(struct statfs *sfsp, unsigned long long used)
293
{
294
162
	prthumanval(sfsp->f_blocks * sfsp->f_bsize);
295
81
	prthumanval(used * sfsp->f_bsize);
296
81
	prthumanval(sfsp->f_bavail * sfsp->f_bsize);
297
81
}
298
299
/*
300
 * Convert statfs returned filesystem size into BLOCKSIZE units.
301
 * Attempts to avoid overflow for large filesystems.
302
 */
303
#define fsbtoblk(num, fsbs, bs) \
304
	(((fsbs) != 0 && (fsbs) < (bs)) ? \
305
		(num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs)))
306
307
/*
308
 * Print out status about a filesystem.
309
 */
310
static void
311
prtstat(struct statfs *sfsp, int maxwidth, int headerlen, int blocksize)
312
{
313
	u_int64_t used, inodes;
314
	int64_t availblks;
315
316
214
	(void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname);
317
107
	used = sfsp->f_blocks - sfsp->f_bfree;
318
107
	availblks = sfsp->f_bavail + used;
319
107
	if (hflag)
320
81
		prthuman(sfsp, used);
321
	else
322
26
		(void)printf(" %*llu %9llu %9lld", headerlen,
323

104
		    fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
324

104
		    fsbtoblk(used, sfsp->f_bsize, blocksize),
325

104
		    fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize));
326
107
	(void)printf(" %5.0f%%",
327
321
	    availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
328
107
	if (iflag) {
329
9
		inodes = sfsp->f_files;
330
9
		used = inodes - sfsp->f_ffree;
331
9
		(void)printf(" %7llu %7llu %5.0f%% ", used, sfsp->f_ffree,
332
27
		   inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
333
9
	} else
334
98
		(void)printf("  ");
335
107
	(void)printf("  %s\n", sfsp->f_mntonname);
336
107
}
337
338
/*
339
 * Print in traditional BSD format.
340
 */
341
static void
342
bsdprint(struct statfs *mntbuf, long mntsize, int maxwidth)
343
{
344
	int i;
345
	char *header;
346
38
	int headerlen;
347
19
	long blocksize;
348
349
	/* Print the header line */
350
19
	if (hflag) {
351
		header = "   Size";
352
9
		headerlen = strlen(header);
353
9
		(void)printf("%-*.*s %s    Used   Avail Capacity",
354
			     maxwidth, maxwidth, "Filesystem", header);
355
9
	} else {
356
10
		if (kflag) {
357
1
			blocksize = 1024;
358
			header = "1K-blocks";
359
1
			headerlen = strlen(header);
360
1
		} else
361
9
			header = getbsize(&headerlen, &blocksize);
362
10
		(void)printf("%-*.*s %s      Used     Avail Capacity",
363
			     maxwidth, maxwidth, "Filesystem", header);
364
	}
365
19
	if (iflag)
366
1
		(void)printf(" iused   ifree  %%iused");
367
19
	(void)printf("  Mounted on\n");
368
369
370
252
	for (i = 0; i < mntsize; i++)
371
107
		prtstat(&mntbuf[i], maxwidth, headerlen, blocksize);
372
	return;
373
19
}
374
375
/*
376
 * Print in format defined by POSIX 1002.2, invoke with -P option.
377
 */
378
static void
379
posixprint(struct statfs *mntbuf, long mntsize, int maxwidth)
380
{
381
	int i;
382
	int blocksize;
383
	char *blockstr;
384
	struct statfs *sfsp;
385
	long long used, avail;
386
	double percentused;
387
388
208
	if (kflag) {
389
		blocksize = 1024;
390
		blockstr = "1024-blocks";
391
	} else {
392
		blocksize = 512;
393
		blockstr = " 512-blocks";
394
	}
395
396
104
	(void)printf(
397
	    "%-*.*s %s       Used   Available Capacity Mounted on\n",
398
	    maxwidth, maxwidth, "Filesystem", blockstr);
399
400
416
	for (i = 0; i < mntsize; i++) {
401
104
		sfsp = &mntbuf[i];
402
104
		used = sfsp->f_blocks - sfsp->f_bfree;
403
104
		avail = sfsp->f_bavail + used;
404
104
		if (avail == 0)
405
			percentused = 100.0;
406
		else
407
104
			percentused = (double)used / (double)avail * 100.0;
408
409
104
		(void) printf ("%-*.*s %*lld %10lld %11lld %5.0f%%   %s\n",
410
104
			maxwidth, maxwidth, sfsp->f_mntfromname,
411
104
			(int)strlen(blockstr),
412

416
			fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
413

416
			fsbtoblk(used, sfsp->f_bsize, blocksize),
414

416
			fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize),
415
104
			percentused, sfsp->f_mntonname);
416
	}
417
104
}
418
419
static int
420
raw_df(char *file, struct statfs *sfsp)
421
{
422
	int rfd, ret = -1;
423
424
	if ((rfd = open(file, O_RDONLY)) < 0) {
425
		warn("%s", file);
426
		return (-1);
427
	}
428
429
	if (ffs_df(rfd, file, sfsp) == 0) {
430
		ret = 0;
431
	} else if (e2fs_df(rfd, file, sfsp) == 0) {
432
		ret = 0;
433
	}
434
435
	close (rfd);
436
	return (ret);
437
}
438
439
int
440
bread(int rfd, off_t off, void *buf, int cnt)
441
{
442
	int nr;
443
444
	if ((nr = pread(rfd, buf, cnt, off)) != cnt) {
445
		/* Probably a dismounted disk if errno == EIO. */
446
		if (errno != EIO)
447
			(void)fprintf(stderr, "\ndf: %lld: %s\n",
448
			    (long long)off, strerror(nr > 0 ? EIO : errno));
449
		return (0);
450
	}
451
	return (1);
452
}
453
454
static __dead void
455
usage(void)
456
{
457
	(void)fprintf(stderr,
458
	    "usage: %s [-hiklnP] [-t type] [[file | file_system] ...]\n",
459
	    getprogname());
460
	exit(1);
461
}