1 /* $NetBSD: df.c,v 1.85 2009/01/25 14:18:21 lukem Exp $ */
4 * Copyright (c) 1980, 1990, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/cdefs.h>
40 "@(#) Copyright (c) 1980, 1990, 1993, 1994\
41 The Regents of the University of California. All rights reserved.");
46 static char sccsid
[] = "@(#)df.c 8.7 (Berkeley) 4/2/94";
48 __RCSID("$NetBSD: df.c,v 1.85 2009/01/25 14:18:21 lukem Exp $");
52 #include <sys/param.h>
54 #include <sys/mount.h>
67 extern char *strpct(u_long
, u_long
, u_int
);
69 int main(int, char *[]);
70 int bread(off_t
, void *, int);
71 char *getmntpt(char *);
72 void prtstat(struct statvfs
*, int);
73 int selected(const char *, size_t);
74 void maketypelist(char *);
75 long regetmntinfo(struct statvfs
**, long);
77 void prthumanval(int64_t, const char *);
78 void prthuman(struct statvfs
*, int64_t, int64_t);
80 strpct64(uint64_t, uint64_t, u_int
);
82 int aflag
, gflag
, hflag
, iflag
, lflag
, nflag
, Pflag
;
84 char **typelist
= NULL
;
87 main(int argc
, char *argv
[])
90 struct statvfs
*mntbuf
;
92 int ch
, i
, maxwidth
, width
;
96 (void)setlocale(LC_ALL
, "");
98 while ((ch
= getopt(argc
, argv
, "aGghiklmnPt:")) != -1)
105 usize
= 1024 * 1024 * 1024;
135 if (typelist
!= NULL
)
137 "only one -t option may be specified.");
138 maketypelist(optarg
);
145 if (gflag
&& (Pflag
|| iflag
))
147 "only one of -G and -P or -i may be specified");
150 "only one of -P and -i may be specified");
153 * The block size cannot be checked until after getbsize() is called.
155 if (Pflag
&& (hflag
|| (usize
!= 1024 && usize
!= 512)))
157 "non-standard block size incompatible with -P");
162 mntsize
= getmntinfo(&mntbuf
, MNT_NOWAIT
);
165 "retrieving information on mounted file systems");
168 mntsize
= regetmntinfo(&mntbuf
, mntsize
);
170 if ((mntbuf
= malloc(argc
* sizeof(*mntbuf
))) == NULL
)
171 err(EXIT_FAILURE
, "can't allocate statvfs array");
173 for (/*EMPTY*/; *argv
!= NULL
; argv
++) {
174 if (stat(*argv
, &stbuf
) < 0) {
175 if ((mntpt
= getmntpt(*argv
)) == 0) {
179 } else if (S_ISBLK(stbuf
.st_mode
)) {
180 if ((mntpt
= getmntpt(*argv
)) == 0)
185 * Statfs does not take a `wait' flag, so we cannot
186 * implement nflag here.
188 if (!statvfs(mntpt
, &mntbuf
[mntsize
]))
190 (mntbuf
[mntsize
].f_flag
& MNT_LOCAL
) == 0)
191 warnx("Warning: %s is not a local %s",
192 *argv
, "file system");
194 (!selected(mntbuf
[mntsize
].f_fstypename
,
195 sizeof(mntbuf
[mntsize
].f_fstypename
)))
196 warnx("Warning: %s mounted as a %s %s",
198 mntbuf
[mntsize
].f_fstypename
,
208 for (i
= 0; i
< mntsize
; i
++) {
209 width
= (int)strlen(mntbuf
[i
].f_mntfromname
);
210 if (width
> maxwidth
)
213 for (i
= 0; i
< mntsize
; i
++)
214 prtstat(&mntbuf
[i
], maxwidth
);
223 struct statvfs
*mntbuf
;
225 mntsize
= getmntinfo(&mntbuf
, MNT_NOWAIT
);
226 for (i
= 0; i
< mntsize
; i
++) {
227 if (!strcmp(mntbuf
[i
].f_mntfromname
, name
))
228 return (mntbuf
[i
].f_mntonname
);
233 static enum { IN_LIST
, NOT_IN_LIST
} which
;
236 selected(const char *type
, size_t len
)
240 /* If no type specified, it's always selected. */
241 if (typelist
== NULL
)
243 for (av
= typelist
; *av
!= NULL
; ++av
)
244 if (!strncmp(type
, *av
, len
))
245 return (which
== IN_LIST
? 1 : 0);
246 return (which
== IN_LIST
? 0 : 1);
250 maketypelist(char *fslist
)
255 if ((fslist
== NULL
) || (fslist
[0] == '\0'))
256 errx(EXIT_FAILURE
, "empty type list");
260 * Note: the syntax is "noxxx,yyy" for no xxx's and
261 * no yyy's, not the more intuitive "noyyy,noyyy".
263 if (fslist
[0] == 'n' && fslist
[1] == 'o') {
269 /* Count the number of types. */
270 for (i
= 1, nextcp
= fslist
;
271 (nextcp
= strchr(nextcp
, ',')) != NULL
; i
++)
274 /* Build an array of that many types. */
275 if ((av
= typelist
= malloc((i
+ 1) * sizeof(char *))) == NULL
)
276 err(EXIT_FAILURE
, "can't allocate type array");
278 for (i
= 1, nextcp
= fslist
;
279 (nextcp
= strchr(nextcp
, ',')) != NULL
; i
++) {
283 /* Terminate the array. */
288 * Make a pass over the filesystem info in ``mntbuf'' filtering out
289 * filesystem types not in ``fsmask'' and possibly re-stating to get
290 * current (not cached) info. Returns the new count of valid statvfs bufs.
293 regetmntinfo(struct statvfs
**mntbufp
, long mntsize
)
296 struct statvfs
*mntbuf
;
298 if (!lflag
&& typelist
== NULL
&& aflag
)
299 return (nflag
? mntsize
: getmntinfo(mntbufp
, MNT_WAIT
));
303 for (i
= 0; i
< mntsize
; i
++) {
304 if (!aflag
&& (mntbuf
[i
].f_flag
& MNT_IGNORE
) != 0)
306 if (lflag
&& (mntbuf
[i
].f_flag
& MNT_LOCAL
) == 0)
308 if (!selected(mntbuf
[i
].f_fstypename
,
309 sizeof(mntbuf
[i
].f_fstypename
)))
312 mntbuf
[j
] = mntbuf
[i
];
314 struct statvfs layerbuf
= mntbuf
[i
];
315 (void)statvfs(mntbuf
[i
].f_mntonname
, &mntbuf
[j
]);
317 * If the FS name changed, then new data is for
318 * a different layer and we don't want it.
320 if (memcmp(layerbuf
.f_mntfromname
,
321 mntbuf
[j
].f_mntfromname
, MNAMELEN
))
322 mntbuf
[j
] = layerbuf
;
330 prthumanval(int64_t bytes
, const char *pad
)
334 (void)humanize_number(buf
, sizeof(buf
) - (bytes
< 0 ? 0 : 1),
335 bytes
, "", HN_AUTOSCALE
,
336 HN_B
| HN_NOSPACE
| HN_DECIMAL
);
338 (void)printf("%s %6s", pad
, buf
);
342 prthuman(struct statvfs
*sfsp
, int64_t used
, int64_t bavail
)
345 prthumanval((int64_t)(sfsp
->f_blocks
* sfsp
->f_frsize
), " ");
346 prthumanval((int64_t)(used
* sfsp
->f_frsize
), " ");
347 prthumanval((int64_t)(bavail
* sfsp
->f_frsize
), " ");
351 * Convert statvfs returned filesystem size into BLOCKSIZE units.
352 * Attempts to avoid overflow for large filesystems.
354 #define fsbtoblk(num, fsbs, bs) \
355 (((fsbs) != 0 && (uint64_t)(fsbs) < (uint64_t)(bs)) ? \
356 (int64_t)(num) / (int64_t)((bs) / (fsbs)) : \
357 (int64_t)(num) * (int64_t)((fsbs) / (bs)))
360 * Print out status about a filesystem.
363 prtstat(struct statvfs
*sfsp
, int maxwidth
)
365 static long blocksize
;
366 static int headerlen
, timesthrough
;
367 static const char *header
;
368 static const char full
[] = "100%";
369 static const char empty
[] = " 0%";
370 int64_t used
, availblks
, inodes
;
377 * /var (/dev/dsk/c0t0d0s3 ): 8192 block size 1024 frag size
378 * 984242 total blocks 860692 free blocks 859708 available 249984 total files
379 * 248691 free files 8388611 filesys id
380 * ufs fstype 0x00000004 flag 255 filename length
383 (void)printf("%10s (%-12s): %7ld block size %12ld frag size\n",
384 sfsp
->f_mntonname
, sfsp
->f_mntfromname
,
385 sfsp
->f_iosize
, /* On UFS/FFS systems this is
386 * also called the "optimal
387 * transfer block size" but it
388 * is of course the file
389 * system's block size too.
391 sfsp
->f_bsize
); /* not so surprisingly the
392 * "fundamental file system
393 * block size" is the frag
396 (void)printf("%10" PRId64
" total blocks %10" PRId64
397 " free blocks %10" PRId64
" available\n",
398 (uint64_t)sfsp
->f_blocks
, (uint64_t)sfsp
->f_bfree
,
399 (uint64_t)sfsp
->f_bavail
);
400 (void)printf("%10" PRId64
" total files %10" PRId64
401 " free files %12lx filesys id\n",
402 (uint64_t)sfsp
->f_ffree
, (uint64_t)sfsp
->f_files
,
404 (void)printf("%10s fstype %#15lx flag %17ld filename "
405 "length\n", sfsp
->f_fstypename
, sfsp
->f_flag
,
407 (void)printf("%10lu owner %17" PRId64
" syncwrites %12" PRId64
408 " asyncwrites\n\n", (unsigned long)sfsp
->f_owner
,
409 sfsp
->f_syncwrites
, sfsp
->f_asyncwrites
);
412 * a concession by the structured programming police to the
413 * indentation police....
419 if (++timesthrough
== 1) {
420 switch (blocksize
= usize
) {
422 header
= Pflag
? "1024-blocks" : "1K-blocks";
423 headerlen
= (int)strlen(header
);
426 header
= "1M-blocks";
427 headerlen
= (int)strlen(header
);
429 case 1024 * 1024 * 1024:
430 header
= "1G-blocks";
431 headerlen
= (int)strlen(header
);
436 headerlen
= (int)strlen(header
);
438 header
= getbsize(&headerlen
, &blocksize
);
444 * "Filesystem 1024-blocks Used Available Capacity Mounted on\n"
446 * "Filesystem 512-blocks Used Available Capacity Mounted on\n"
448 if (blocksize
!= 1024 && blocksize
!= 512)
450 "non-standard block size incompatible with -P");
451 (void)printf("Filesystem %s Used Available Capacity "
452 "Mounted on\n", header
);
454 (void)printf("%-*.*s %s Used Avail %%Cap",
455 maxwidth
- (headerlen
- 9),
456 maxwidth
- (headerlen
- 9),
457 "Filesystem", header
);
459 (void)printf(" iUsed iAvail %%iCap");
460 (void)printf(" Mounted on\n");
463 used
= sfsp
->f_blocks
- sfsp
->f_bfree
;
464 bavail
= sfsp
->f_bfree
- sfsp
->f_bresvd
;
465 availblks
= bavail
+ used
;
468 assert(blocksize
> 0);
470 * "%s %d %d %d %s %s\n", <file system name>, <total space>,
471 * <space used>, <space free>, <percentage used>,
474 (void)printf("%s %" PRId64
" %" PRId64
" %" PRId64
" %s %s\n",
476 fsbtoblk(sfsp
->f_blocks
, sfsp
->f_frsize
, blocksize
),
477 fsbtoblk(used
, sfsp
->f_frsize
, blocksize
),
478 fsbtoblk(bavail
, sfsp
->f_frsize
, blocksize
),
479 availblks
== 0 ? full
: strpct64((uint64_t) used
,
480 (uint64_t) availblks
, 0), sfsp
->f_mntonname
);
482 * another concession by the structured programming police to
483 * the indentation police....
485 * Note iflag cannot be set when Pflag is set.
490 (void)printf("%-*.*s ", maxwidth
, maxwidth
, sfsp
->f_mntfromname
);
493 prthuman(sfsp
, used
, bavail
);
495 (void)printf("%10" PRId64
" %10" PRId64
" %10" PRId64
,
496 fsbtoblk(sfsp
->f_blocks
, sfsp
->f_frsize
, blocksize
),
497 fsbtoblk(used
, sfsp
->f_frsize
, blocksize
),
498 fsbtoblk(bavail
, sfsp
->f_frsize
, blocksize
));
500 availblks
== 0 ? full
:
501 /* We know that these values are never negative */
502 strpct64((uint64_t)used
, (uint64_t)availblks
, 0));
504 inodes
= sfsp
->f_files
;
505 used
= inodes
- sfsp
->f_ffree
;
506 (void)printf(" %8jd %8jd %4s",
507 (intmax_t)used
, (intmax_t)sfsp
->f_ffree
,
508 inodes
== 0 ? (used
== 0 ? empty
: full
) :
509 strpct64((uint64_t)used
, (uint64_t)inodes
, 0));
511 (void)printf(" %s\n", sfsp
->f_mntonname
);
518 (void)fprintf(stderr
,
519 "Usage: %s [-aGgln] [-hkm|-ihkm|-Pk] [-t type] [file | "
520 "file_system ...]\n",
527 strpct64(uint64_t numerator
, uint64_t denominator
, u_int digits
)
530 while (denominator
> ULONG_MAX
) {
534 return (strpct((u_long
)numerator
, (u_long
)denominator
, digits
));