1 /* $NetBSD: df.c,v 1.92.8.1 2018/08/28 13:21:42 martin 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.92.8.1 2018/08/28 13:21:42 martin Exp $");
52 #include <sys/param.h>
54 #include <sys/mount.h>
68 static char *getmntpt(const char *);
69 static void prtstat(struct statvfs
*, int);
70 static int selected(const char *, size_t);
71 static void maketypelist(char *);
72 static size_t regetmntinfo(struct statvfs
**, size_t);
73 __dead
static void usage(void);
74 static void prthumanval(int64_t, const char *);
75 static void prthuman(struct statvfs
*, int64_t, int64_t);
77 static int aflag
, gflag
, hflag
, iflag
, lflag
, nflag
, Pflag
;
79 static char **typelist
;
82 main(int argc
, char *argv
[])
85 struct statvfs
*mntbuf
;
87 int ch
, i
, maxwidth
, width
;
91 (void)setlocale(LC_ALL
, "");
93 while ((ch
= getopt(argc
, argv
, "aGghiklmnPt:")) != -1)
100 usize
= 1024 * 1024 * 1024;
130 if (typelist
!= NULL
)
132 "only one -t option may be specified.");
133 maketypelist(optarg
);
140 if (gflag
&& (Pflag
|| iflag
))
142 "only one of -G and -P or -i may be specified");
145 "only one of -P and -i may be specified");
148 * The block size cannot be checked until after getbsize() is called.
150 if (Pflag
&& (hflag
|| (usize
!= 1024 && usize
!= 512)))
152 "non-standard block size incompatible with -P");
157 mntsize
= getmntinfo(&mntbuf
, MNT_NOWAIT
);
160 "retrieving information on mounted file systems");
163 mntsize
= regetmntinfo(&mntbuf
, mntsize
);
165 if ((mntbuf
= malloc(argc
* sizeof(*mntbuf
))) == NULL
)
166 err(EXIT_FAILURE
, "can't allocate statvfs array");
168 for (/*EMPTY*/; *argv
!= NULL
; argv
++) {
169 if (stat(*argv
, &stbuf
) < 0) {
170 if ((mntpt
= getmntpt(*argv
)) == 0) {
174 } else if (S_ISBLK(stbuf
.st_mode
)) {
175 if ((mntpt
= getmntpt(*argv
)) == 0)
180 * Statfs does not take a `wait' flag, so we cannot
181 * implement nflag here.
183 if (!statvfs(mntpt
, &mntbuf
[mntsize
]))
185 (mntbuf
[mntsize
].f_flag
& MNT_LOCAL
) == 0)
186 warnx("Warning: %s is not a local %s",
187 *argv
, "file system");
189 (!selected(mntbuf
[mntsize
].f_fstypename
,
190 sizeof(mntbuf
[mntsize
].f_fstypename
)))
191 warnx("Warning: %s mounted as a %s %s",
193 mntbuf
[mntsize
].f_fstypename
,
203 for (i
= 0; i
< mntsize
; i
++) {
204 width
= (int)strlen(mntbuf
[i
].f_mntfromname
);
205 if (width
> maxwidth
)
208 for (i
= 0; i
< mntsize
; i
++)
209 prtstat(&mntbuf
[i
], maxwidth
);
214 getmntpt(const char *name
)
217 struct statvfs
*mntbuf
;
219 mntsize
= getmntinfo(&mntbuf
, MNT_NOWAIT
);
221 err(EXIT_FAILURE
, "Can't get mount information");
222 for (i
= 0; i
< mntsize
; i
++) {
223 if (!strcmp(mntbuf
[i
].f_mntfromname
, name
))
224 return mntbuf
[i
].f_mntonname
;
229 static enum { IN_LIST
, NOT_IN_LIST
} which
;
232 selected(const char *type
, size_t len
)
236 /* If no type specified, it's always selected. */
237 if (typelist
== NULL
)
239 for (av
= typelist
; *av
!= NULL
; ++av
)
240 if (!strncmp(type
, *av
, len
))
241 return which
== IN_LIST
? 1 : 0;
242 return which
== IN_LIST
? 0 : 1;
246 maketypelist(char *fslist
)
251 if ((fslist
== NULL
) || (fslist
[0] == '\0'))
252 errx(EXIT_FAILURE
, "empty type list");
256 * Note: the syntax is "noxxx,yyy" for no xxx's and
257 * no yyy's, not the more intuitive "noyyy,noyyy".
259 if (fslist
[0] == 'n' && fslist
[1] == 'o') {
265 /* Count the number of types. */
266 for (i
= 1, nextcp
= fslist
;
267 (nextcp
= strchr(nextcp
, ',')) != NULL
; i
++)
270 /* Build an array of that many types. */
271 if ((av
= typelist
= malloc((i
+ 1) * sizeof(*av
))) == NULL
)
272 err(EXIT_FAILURE
, "can't allocate type array");
274 for (i
= 1, nextcp
= fslist
;
275 (nextcp
= strchr(nextcp
, ',')) != NULL
; i
++) {
279 /* Terminate the array. */
284 * Make a pass over the filesystem info in ``mntbuf'' filtering out
285 * filesystem types not in ``fsmask'' and possibly re-stating to get
286 * current (not cached) info. Returns the new count of valid statvfs bufs.
289 regetmntinfo(struct statvfs
**mntbufp
, size_t mntsize
)
292 struct statvfs
*mntbuf
;
294 if (!lflag
&& typelist
== NULL
&& aflag
)
295 return nflag
? mntsize
: (size_t)getmntinfo(mntbufp
, MNT_WAIT
);
299 for (i
= 0; i
< mntsize
; i
++) {
300 if (!aflag
&& (mntbuf
[i
].f_flag
& MNT_IGNORE
) != 0)
302 if (lflag
&& (mntbuf
[i
].f_flag
& MNT_LOCAL
) == 0)
304 if (!selected(mntbuf
[i
].f_fstypename
,
305 sizeof(mntbuf
[i
].f_fstypename
)))
308 mntbuf
[j
] = mntbuf
[i
];
310 struct statvfs layerbuf
= mntbuf
[i
];
311 (void)statvfs(mntbuf
[i
].f_mntonname
, &mntbuf
[j
]);
313 * If the FS name changed, then new data is for
314 * a different layer and we don't want it.
316 if (memcmp(layerbuf
.f_mntfromname
,
317 mntbuf
[j
].f_mntfromname
, MNAMELEN
))
318 mntbuf
[j
] = layerbuf
;
326 prthumanval(int64_t bytes
, const char *pad
)
330 (void)humanize_number(buf
, sizeof(buf
) - (bytes
< 0 ? 0 : 1),
331 bytes
, "", HN_AUTOSCALE
,
332 HN_B
| HN_NOSPACE
| HN_DECIMAL
);
334 (void)printf("%s %6s", pad
, buf
);
338 prthuman(struct statvfs
*sfsp
, int64_t used
, int64_t bavail
)
341 prthumanval((int64_t)(sfsp
->f_blocks
* sfsp
->f_frsize
), " ");
342 prthumanval((int64_t)(used
* sfsp
->f_frsize
), " ");
343 prthumanval((int64_t)(bavail
* sfsp
->f_frsize
), " ");
347 * Convert statvfs returned filesystem size into BLOCKSIZE units.
348 * Attempts to avoid overflow for large filesystems.
350 #define fsbtoblk(num, fsbs, bs) \
351 (((fsbs) != 0 && (uint64_t)(fsbs) < (uint64_t)(bs)) ? \
352 (int64_t)(num) / (int64_t)((bs) / (fsbs)) : \
353 (int64_t)(num) * (int64_t)((fsbs) / (bs)))
356 * Print out status about a filesystem.
359 prtstat(struct statvfs
*sfsp
, int maxwidth
)
361 static long blocksize
;
362 static int headerlen
, timesthrough
;
363 static const char *header
;
364 static const char full
[] = "100";
365 static const char empty
[] = " 0";
366 int64_t used
, availblks
, inodes
;
374 * /var (/dev/dsk/c0t0d0s3 ): 8192 block size 1024 frag size
375 * 984242 total blocks 860692 free blocks 859708 available 249984 total files
376 * 248691 free files 8388611 filesys id
377 * ufs fstype 0x00000004 flag 255 filename length
380 (void)printf("%10s (%-12s): %7ld block size %12ld frag size\n",
381 sfsp
->f_mntonname
, sfsp
->f_mntfromname
,
382 sfsp
->f_bsize
, /* On UFS/FFS systems this is
383 * also called the "optimal
384 * transfer block size" but it
385 * is of course the file
386 * system's block size too.
388 sfsp
->f_frsize
); /* not so surprisingly the
389 * "fundamental file system
390 * block size" is the frag
393 (void)printf("%10" PRId64
" total blocks %10" PRId64
394 " free blocks %10" PRId64
" available\n",
395 (uint64_t)sfsp
->f_blocks
, (uint64_t)sfsp
->f_bfree
,
396 (uint64_t)sfsp
->f_bavail
);
397 (void)printf("%10" PRId64
" total files %10" PRId64
398 " free files %12lx filesys id\n",
399 (uint64_t)sfsp
->f_ffree
, (uint64_t)sfsp
->f_files
,
401 (void)printf("%10s fstype %#15lx flag %17ld filename "
402 "length\n", sfsp
->f_fstypename
, sfsp
->f_flag
,
404 (void)printf("%10lu owner %17" PRId64
" syncwrites %12" PRId64
405 " asyncwrites\n\n", (unsigned long)sfsp
->f_owner
,
406 sfsp
->f_syncwrites
, sfsp
->f_asyncwrites
);
409 * a concession by the structured programming police to the
410 * indentation police....
416 if (++timesthrough
== 1) {
417 switch (blocksize
= usize
) {
419 header
= Pflag
? "1024-blocks" : "1K-blocks";
420 headerlen
= (int)strlen(header
);
423 header
= "1M-blocks";
424 headerlen
= (int)strlen(header
);
426 case 1024 * 1024 * 1024:
427 header
= "1G-blocks";
428 headerlen
= (int)strlen(header
);
433 headerlen
= (int)strlen(header
);
435 header
= getbsize(&headerlen
, &blocksize
);
441 * "Filesystem 1024-blocks Used Available Capacity Mounted on\n"
443 * "Filesystem 512-blocks Used Available Capacity Mounted on\n"
445 if (blocksize
!= 1024 && blocksize
!= 512)
447 "non-standard block size incompatible with -P");
448 (void)printf("Filesystem %s Used Available Capacity "
449 "Mounted on\n", header
);
451 (void)printf("%-*.*s %s Used Avail %%Cap",
452 maxwidth
- (headerlen
- 10),
453 maxwidth
- (headerlen
- 10),
454 "Filesystem", header
);
456 (void)printf(" iUsed iAvail %%iCap");
457 (void)printf(" Mounted on\n");
460 used
= sfsp
->f_blocks
- sfsp
->f_bfree
;
461 bavail
= sfsp
->f_bfree
- sfsp
->f_bresvd
;
462 availblks
= bavail
+ used
;
465 assert(blocksize
> 0);
467 * "%s %d %d %d %s %s\n", <file system name>, <total space>,
468 * <space used>, <space free>, <percentage used>,
471 (void)printf("%s %" PRId64
" %" PRId64
" %" PRId64
" %s%% %s\n",
473 fsbtoblk(sfsp
->f_blocks
, sfsp
->f_frsize
, blocksize
),
474 fsbtoblk(used
, sfsp
->f_frsize
, blocksize
),
475 fsbtoblk(bavail
, sfsp
->f_frsize
, blocksize
),
476 availblks
== 0 ? full
: strspct(pb
, sizeof(pb
), used
,
477 availblks
, 0), sfsp
->f_mntonname
);
479 * another concession by the structured programming police to
480 * the indentation police....
482 * Note iflag cannot be set when Pflag is set.
487 (void)printf("%-*.*s ", maxwidth
, maxwidth
, sfsp
->f_mntfromname
);
490 prthuman(sfsp
, used
, bavail
);
492 (void)printf("%10" PRId64
" %10" PRId64
" %10" PRId64
,
493 fsbtoblk(sfsp
->f_blocks
, sfsp
->f_frsize
, blocksize
),
494 fsbtoblk(used
, sfsp
->f_frsize
, blocksize
),
495 fsbtoblk(bavail
, sfsp
->f_frsize
, blocksize
));
496 (void)printf(" %3s%%",
497 availblks
== 0 ? full
:
498 strspct(pb
, sizeof(pb
), used
, availblks
, 0));
500 inodes
= sfsp
->f_files
;
501 used
= inodes
- sfsp
->f_ffree
;
502 (void)printf(" %8jd %8jd %4s%%",
503 (intmax_t)used
, (intmax_t)sfsp
->f_ffree
,
504 inodes
== 0 ? (used
== 0 ? empty
: full
) :
505 strspct(pb
, sizeof(pb
), used
, inodes
, 0));
507 (void)printf(" %s\n", sfsp
->f_mntonname
);
514 (void)fprintf(stderr
,
515 "Usage: %s [-agln] [-Ghkm|-ihkm|-Pk] [-t type] [file | "
516 "file_system ...]\n",