diff --git a/bin/df/df.1 b/bin/df/df.1 index d542dbde8067..64e471fedc42 100644 --- a/bin/df/df.1 +++ b/bin/df/df.1 @@ -1,294 +1,297 @@ .\"- .\" Copyright (c) 1989, 1990, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)df.1 8.3 (Berkeley) 5/8/95 .\" $FreeBSD$ .\" -.Dd October 5, 2020 +.Dd March 11, 2022 .Dt DF 1 .Os .Sh NAME .Nm df .Nd display free disk space .Sh SYNOPSIS .Nm .Op Fl -libxo .Op Fl b | g | H | h | k | m | P .Op Fl acilnT .Op Fl \&, .Op Fl t Ar type .Op Ar file | filesystem ... .Sh DESCRIPTION The .Nm utility displays statistics about the amount of free disk space on the specified mounted .Ar file system or on the file system of which .Ar file is a part. By default block counts are displayed with an assumed block size of 512 bytes. If neither a file or a file system operand is specified, statistics for all mounted file systems are displayed (subject to the .Fl t option below). .Pp The following options are available: .Bl -tag -width indent .It Fl -libxo Generate output via .Xr libxo 3 in a selection of different human and machine readable formats. See .Xr xo_parse_args 3 for details on command line arguments. .It Fl a Show all mount points, including those that were mounted with the .Dv MNT_IGNORE flag. This is implied for file systems specified on the command line. .It Fl b Explicitly use 512 byte blocks, overriding any .Ev BLOCKSIZE specification from the environment. This is the same as the .Fl P option. The .Fl k option overrides this option. .It Fl c Display a grand total. .It Fl g Use 1073741824 byte (1 Gibibyte) blocks rather than the default. This overrides any .Ev BLOCKSIZE specification from the environment. .It Fl h .Dq Human-readable output. Use unit suffixes: Byte, Kibibyte, Mebibyte, Gibibyte, Tebibyte and Pebibyte (based on powers of 1024) in order to reduce the number of digits to four or fewer. .It Fl H , Fl Fl si Same as .Fl h but based on powers of 1000. .It Fl i Include statistics on the number of free and used inodes. In conjunction with the .Fl h or .Fl H options, the number of inodes is scaled by powers of 1000. +In case the filesystem has no inodes then +.Sq - +is displayed instead of the usage percentage. .It Fl k Use 1024 byte (1 Kibibyte) blocks rather than the default. This overrides the .Fl P option and any .Ev BLOCKSIZE specification from the environment. .It Fl l Select locally-mounted file system for display. If used in combination with the .Fl t Ar type option, file system types will be added or excluded acccording to the parameters of that option. .It Fl m Use 1048576 byte (1 Mebibyte) blocks rather than the default. This overrides any .Ev BLOCKSIZE specification from the environment. .It Fl n Print out the previously obtained statistics from the file systems. This option should be used if it is possible that one or more file systems are in a state such that they will not be able to provide statistics without a long delay. When this option is specified, .Nm will not request new statistics from the file systems, but will respond with the possibly stale statistics that were previously obtained. .It Fl P Explicitly use 512 byte blocks, overriding any .Ev BLOCKSIZE specification from the environment. This is the same as the .Fl b option. The .Fl k option overrides this option. .It Fl t Ar type Select file systems to display. More than one type may be specified in a comma separated list. The list of file system types can be prefixed with .Dq no to specify the file system types for which action should .Em not be taken. If used in combination with the .Fl l option, the parameters of this option will modify the list of locally-mounted file systems selected by the .Fl l option. For example, the .Nm command: .Bd -literal -offset indent df -t nonfs,nullfs .Ed .Pp lists all file systems except those of type NFS and NULLFS. The .Xr lsvfs 1 command can be used to find out the types of file systems that are available on the system. .It Fl T Include file system type. .It Fl , (Comma) Print sizes grouped and separated by thousands using the non-monetary separator returned by .Xr localeconv 3 , typically a comma or period. If no locale is set, or the locale does not have a non-monetary separator, this option has no effect. .El .Sh ENVIRONMENT .Bl -tag -width BLOCKSIZE .It Ev BLOCKSIZE Specifies the units in which to report block counts. This uses .Xr getbsize 3 , which allows units of bytes or numbers scaled with the letters .Em k (for multiples of 1024 bytes), .Em m (for multiples of 1048576 bytes) or .Em g (for gibibytes). The allowed range is 512 bytes to 1 GB. If the value is outside, it will be set to the appropriate limit. .El .Sh EXAMPLES Show human readable free disk space for all mount points including file system type: .Bd -literal -offset indent $ df -ahT Filesystem Type Size Used Avail Capacity Mounted on /dev/ada1p2 ufs 213G 152G 44G 78% / devfs devfs 1.0K 1.0K 0B 100% /dev /dev/ada0p1 ufs 1.8T 168G 1.5T 10% /data linsysfs linsysfs 4.0K 4.0K 0B 100% /compat/linux/sys /dev/da0 msdosfs 7.6G 424M 7.2G 5% /mnt/usb .Ed .Pp Show previously collected data including inode statistics except for devfs or linsysfs file systems. Note that the .Dq no prefix affects all the file systems in the list and the .Fl t option can be specified only once: .Bd -literal -offset indent $ df -i -n -t nodevfs,linsysfs Filesystem 1K-blocks Used Avail Capacity iused ifree %iused Mounted on /dev/ada1p2 223235736 159618992 45757888 78% 1657590 27234568 6% / /dev/ada0p1 1892163184 176319420 1564470712 10% 1319710 243300576 1% /data /dev/da0 7989888 433664 7556224 5% 0 0 100% /mnt/usb .Ed .Pp Show human readable information for the file system containing the file .Pa /etc/rc.conf : .Bd -literal -offset indent $ df -h /etc/rc.conf Filesystem Size Used Avail Capacity Mounted on /dev/ada1p2 213G 152G 44G 78% / .Ed .Pp Same as above but specifying some file system: .Bd -literal -offset indent $ df -h /dev/ada1p2 Filesystem Size Used Avail Capacity Mounted on /dev/ada1p2 213G 152G 44G 78% / .Ed .Sh SEE ALSO .Xr lsvfs 1 , .Xr quota 1 , .Xr fstatfs 2 , .Xr getfsstat 2 , .Xr statfs 2 , .Xr getbsize 3 , .Xr getmntinfo 3 , .Xr libxo 3 , .Xr localeconv 3 , .Xr xo_parse_args 3 , .Xr fstab 5 , .Xr mount 8 , .Xr pstat 8 , .Xr quot 8 , .Xr swapinfo 8 .Sh STANDARDS With the exception of most options, the .Nm utility conforms to .St -p1003.1-2004 , which defines only the .Fl k , P and .Fl t options. .Sh HISTORY A .Nm command appeared in .At v1 . .Sh BUGS The .Fl n flag is ignored if a file or file system is specified. Also, if a mount point is not accessible by the user, it is possible that the file system information could be stale. .Pp The .Fl b and .Fl P options are identical. The former comes from the BSD tradition, and the latter is required for .St -p1003.1-2004 conformity. diff --git a/bin/df/df.c b/bin/df/df.c index 63c37de92d62..627d8b1c861d 100644 --- a/bin/df/df.c +++ b/bin/df/df.c @@ -1,710 +1,713 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1980, 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1990, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)df.c 8.9 (Berkeley) 5/8/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define UNITS_SI 1 #define UNITS_2 2 /* Maximum widths of various fields. */ struct maxwidths { int mntfrom; int fstype; int total; int used; int avail; int iused; int ifree; }; static void addstat(struct statfs *, struct statfs *); static char *getmntpt(const char *); static const char **makevfslist(char *fslist, int *skip); static int checkvfsname(const char *vfsname, const char **vfslist, int skip); static int checkvfsselected(char *); static int int64width(int64_t); static char *makenetvfslist(void); static void prthuman(const struct statfs *, int64_t); static void prthumanval(const char *, int64_t); static intmax_t fsbtoblk(int64_t, uint64_t, u_long); static void prtstat(struct statfs *, struct maxwidths *); static size_t regetmntinfo(struct statfs **, long); static void update_maxwidths(struct maxwidths *, const struct statfs *); static void usage(void); static __inline int imax(int a, int b) { return (a > b ? a : b); } static int aflag = 0, cflag, hflag, iflag, kflag, lflag = 0, nflag, Tflag; static int thousands; static int skipvfs_l, skipvfs_t; static const char **vfslist_l, **vfslist_t; static const struct option long_options[] = { { "si", no_argument, NULL, 'H' }, { NULL, no_argument, NULL, 0 }, }; int main(int argc, char *argv[]) { struct stat stbuf; struct statfs statfsbuf, totalbuf; struct maxwidths maxwidths; struct statfs *mntbuf; char *mntpt; int i, mntsize; int ch, rv; (void)setlocale(LC_ALL, ""); memset(&maxwidths, 0, sizeof(maxwidths)); memset(&totalbuf, 0, sizeof(totalbuf)); totalbuf.f_bsize = DEV_BSIZE; strlcpy(totalbuf.f_mntfromname, "total", MNAMELEN); argc = xo_parse_args(argc, argv); if (argc < 0) exit(1); while ((ch = getopt_long(argc, argv, "+abcgHhiklmnPt:T,", long_options, NULL)) != -1) switch (ch) { case 'a': aflag = 1; break; case 'b': /* FALLTHROUGH */ case 'P': /* * POSIX specifically discusses the behavior of * both -k and -P. It states that the blocksize should * be set to 1024. Thus, if this occurs, simply break * rather than clobbering the old blocksize. */ if (kflag) break; setenv("BLOCKSIZE", "512", 1); hflag = 0; break; case 'c': cflag = 1; break; case 'g': setenv("BLOCKSIZE", "1g", 1); hflag = 0; break; case 'H': hflag = UNITS_SI; break; case 'h': hflag = UNITS_2; break; case 'i': iflag = 1; break; case 'k': kflag++; setenv("BLOCKSIZE", "1024", 1); hflag = 0; break; case 'l': /* Ignore duplicate -l */ if (lflag) break; vfslist_l = makevfslist(makenetvfslist(), &skipvfs_l); lflag = 1; break; case 'm': setenv("BLOCKSIZE", "1m", 1); hflag = 0; break; case 'n': nflag = 1; break; case 't': if (vfslist_t != NULL) xo_errx(1, "only one -t option may be specified"); vfslist_t = makevfslist(optarg, &skipvfs_t); break; case 'T': Tflag = 1; break; case ',': thousands = 1; break; case '?': default: usage(); } argc -= optind; argv += optind; rv = 0; if (!*argv) { /* everything (modulo -t) */ mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); mntsize = regetmntinfo(&mntbuf, mntsize); } else { /* just the filesystems specified on the command line */ mntbuf = malloc(argc * sizeof(*mntbuf)); if (mntbuf == NULL) xo_err(1, "malloc()"); mntsize = 0; /* continued in for loop below */ } xo_open_container("storage-system-information"); xo_open_list("filesystem"); /* iterate through specified filesystems */ for (; *argv; argv++) { if (stat(*argv, &stbuf) < 0) { if ((mntpt = getmntpt(*argv)) == NULL) { xo_warn("%s", *argv); rv = 1; continue; } } else if (S_ISCHR(stbuf.st_mode)) { mntpt = getmntpt(*argv); if (mntpt == NULL) { xo_warnx("%s: not mounted", *argv); rv = 1; continue; } } else { mntpt = *argv; } /* * Statfs does not take a `wait' flag, so we cannot * implement nflag here. */ if (statfs(mntpt, &statfsbuf) < 0) { xo_warn("%s", mntpt); rv = 1; continue; } /* * Check to make sure the arguments we've been given are * satisfied. Return an error if we have been asked to * list a mount point that does not match the other args * we've been given (-l, -t, etc.). */ if (checkvfsselected(statfsbuf.f_fstypename) != 0) { rv = 1; continue; } /* the user asked for it, so ignore the ignore flag */ statfsbuf.f_flags &= ~MNT_IGNORE; /* add to list */ mntbuf[mntsize++] = statfsbuf; } memset(&maxwidths, 0, sizeof(maxwidths)); for (i = 0; i < mntsize; i++) { if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0) { update_maxwidths(&maxwidths, &mntbuf[i]); if (cflag) addstat(&totalbuf, &mntbuf[i]); } } for (i = 0; i < mntsize; i++) if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0) prtstat(&mntbuf[i], &maxwidths); xo_close_list("filesystem"); if (cflag) prtstat(&totalbuf, &maxwidths); xo_close_container("storage-system-information"); xo_finish(); exit(rv); } static char * getmntpt(const char *name) { size_t mntsize, i; struct statfs *mntbuf; mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); for (i = 0; i < mntsize; i++) { if (!strcmp(mntbuf[i].f_mntfromname, name)) return (mntbuf[i].f_mntonname); } return (NULL); } static const char ** makevfslist(char *fslist, int *skip) { const char **av; int i; char *nextcp; if (fslist == NULL) return (NULL); *skip = 0; if (fslist[0] == 'n' && fslist[1] == 'o') { fslist += 2; *skip = 1; } for (i = 0, nextcp = fslist; *nextcp; nextcp++) if (*nextcp == ',') i++; if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) { warnx("malloc failed"); return (NULL); } nextcp = fslist; i = 0; av[i++] = nextcp; while ((nextcp = strchr(nextcp, ',')) != NULL) { *nextcp++ = '\0'; av[i++] = nextcp; } av[i++] = NULL; return (av); } static int checkvfsname(const char *vfsname, const char **vfslist, int skip) { if (vfslist == NULL) return (0); while (*vfslist != NULL) { if (strcmp(vfsname, *vfslist) == 0) return (skip); ++vfslist; } return (!skip); } /* * Without -l and -t option, all file system types are enabled. * The -l option selects the local file systems, if present. * A -t option modifies the selection by adding or removing further * file system types, based on the argument that is passed. */ static int checkvfsselected(char *fstypename) { int result; if (vfslist_t) { /* if -t option used then select passed types */ result = checkvfsname(fstypename, vfslist_t, skipvfs_t); if (vfslist_l) { /* if -l option then adjust selection */ if (checkvfsname(fstypename, vfslist_l, skipvfs_l) == skipvfs_t) result = skipvfs_t; } } else { /* no -t option then -l decides */ result = checkvfsname(fstypename, vfslist_l, skipvfs_l); } return (result); } /* * Make a pass over the file system info in ``mntbuf'' filtering out * file system types not in vfslist_{l,t} and possibly re-stating to get * current (not cached) info. Returns the new count of valid statfs bufs. */ static size_t regetmntinfo(struct statfs **mntbufp, long mntsize) { int error, i, j; struct statfs *mntbuf; if (vfslist_l == NULL && vfslist_t == NULL) return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT)); mntbuf = *mntbufp; for (j = 0, i = 0; i < mntsize; i++) { if (checkvfsselected(mntbuf[i].f_fstypename) != 0) continue; /* * XXX statfs(2) can fail for various reasons. It may be * possible that the user does not have access to the * pathname, if this happens, we will fall back on * "stale" filesystem statistics. */ error = statfs(mntbuf[i].f_mntonname, &mntbuf[j]); if (nflag || error < 0) if (i != j) { if (error < 0) xo_warnx("%s stats possibly stale", mntbuf[i].f_mntonname); mntbuf[j] = mntbuf[i]; } j++; } return (j); } static void prthuman(const struct statfs *sfsp, int64_t used) { prthumanval(" {:blocks/%6s}", sfsp->f_blocks * sfsp->f_bsize); prthumanval(" {:used/%6s}", used * sfsp->f_bsize); prthumanval(" {:available/%6s}", sfsp->f_bavail * sfsp->f_bsize); } static void prthumanval(const char *fmt, int64_t bytes) { char buf[6]; int flags; flags = HN_B | HN_NOSPACE | HN_DECIMAL; if (hflag == UNITS_SI) flags |= HN_DIVISOR_1000; humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), bytes, "", HN_AUTOSCALE, flags); xo_attr("value", "%lld", (long long) bytes); xo_emit(fmt, buf); } /* * Print an inode count in "human-readable" format. */ static void prthumanvalinode(const char *fmt, int64_t bytes) { char buf[6]; int flags; flags = HN_NOSPACE | HN_DECIMAL | HN_DIVISOR_1000; humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), bytes, "", HN_AUTOSCALE, flags); xo_attr("value", "%lld", (long long) bytes); xo_emit(fmt, buf); } /* * Convert statfs returned file system size into BLOCKSIZE units. */ static intmax_t fsbtoblk(int64_t num, uint64_t fsbs, u_long bs) { return (num * (intmax_t) fsbs / (int64_t) bs); } /* * Print out status about a file system. */ static void prtstat(struct statfs *sfsp, struct maxwidths *mwp) { static long blocksize; static int headerlen, timesthrough = 0; static const char *header; int64_t used, availblks, inodes; const char *format; if (++timesthrough == 1) { mwp->mntfrom = imax(mwp->mntfrom, (int)strlen("Filesystem")); mwp->fstype = imax(mwp->fstype, (int)strlen("Type")); if (thousands) { /* make space for commas */ mwp->total += (mwp->total - 1) / 3; mwp->used += (mwp->used - 1) / 3; mwp->avail += (mwp->avail - 1) / 3; mwp->iused += (mwp->iused - 1) / 3; mwp->ifree += (mwp->ifree - 1) / 3; } if (hflag) { header = " Size"; mwp->total = mwp->used = mwp->avail = (int)strlen(header); } else { header = getbsize(&headerlen, &blocksize); mwp->total = imax(mwp->total, headerlen); } mwp->used = imax(mwp->used, (int)strlen("Used")); mwp->avail = imax(mwp->avail, (int)strlen("Avail")); xo_emit("{T:/%-*s}", mwp->mntfrom, "Filesystem"); if (Tflag) xo_emit(" {T:/%-*s}", mwp->fstype, "Type"); xo_emit(" {T:/%*s} {T:/%*s} {T:/%*s} {T:Capacity}", mwp->total, header, mwp->used, "Used", mwp->avail, "Avail"); if (iflag) { mwp->iused = imax(hflag ? 0 : mwp->iused, (int)strlen(" iused")); mwp->ifree = imax(hflag ? 0 : mwp->ifree, (int)strlen("ifree")); xo_emit(" {T:/%*s} {T:/%*s} {T:\%iused}", mwp->iused - 2, "iused", mwp->ifree, "ifree"); } xo_emit(" {T:Mounted on}\n"); } xo_open_instance("filesystem"); /* Check for 0 block size. Can this happen? */ if (sfsp->f_bsize == 0) { xo_warnx ("File system %s does not have a block size, assuming 512.", sfsp->f_mntonname); sfsp->f_bsize = 512; } xo_emit("{tk:name/%-*s}", mwp->mntfrom, sfsp->f_mntfromname); if (Tflag) xo_emit(" {:type/%-*s}", mwp->fstype, sfsp->f_fstypename); used = sfsp->f_blocks - sfsp->f_bfree; availblks = sfsp->f_bavail + used; if (hflag) { prthuman(sfsp, used); } else { if (thousands) format = " {t:total-blocks/%*j'd} {t:used-blocks/%*j'd} " "{t:available-blocks/%*j'd}"; else format = " {t:total-blocks/%*jd} {t:used-blocks/%*jd} " "{t:available-blocks/%*jd}"; xo_emit(format, mwp->total, fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize), mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize), mwp->avail, fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize)); } xo_emit(" {:used-percent/%5.0f}{U:%%}", availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0); if (iflag) { inodes = sfsp->f_files; used = inodes - sfsp->f_ffree; if (hflag) { xo_emit(" "); prthumanvalinode(" {:inodes-used/%5s}", used); prthumanvalinode(" {:inodes-free/%5s}", sfsp->f_ffree); } else { if (thousands) format = " {:inodes-used/%*j'd} {:inodes-free/%*j'd}"; else format = " {:inodes-used/%*jd} {:inodes-free/%*jd}"; xo_emit(format, mwp->iused, (intmax_t)used, mwp->ifree, (intmax_t)sfsp->f_ffree); } - xo_emit(" {:inodes-used-percent/%4.0f}{U:%%} ", - inodes == 0 ? 100.0 : - (double)used / (double)inodes * 100.0); + if (inodes == 0) + xo_emit(" {:inodes-used-percent/ -}{U:} "); + else { + xo_emit(" {:inodes-used-percent/%4.0f}{U:%%} ", + (double)used / (double)inodes * 100.0); + } } else xo_emit(" "); if (strncmp(sfsp->f_mntfromname, "total", MNAMELEN) != 0) xo_emit(" {:mounted-on}", sfsp->f_mntonname); xo_emit("\n"); xo_close_instance("filesystem"); } static void addstat(struct statfs *totalfsp, struct statfs *statfsp) { uint64_t bsize; bsize = statfsp->f_bsize / totalfsp->f_bsize; totalfsp->f_blocks += statfsp->f_blocks * bsize; totalfsp->f_bfree += statfsp->f_bfree * bsize; totalfsp->f_bavail += statfsp->f_bavail * bsize; totalfsp->f_files += statfsp->f_files; totalfsp->f_ffree += statfsp->f_ffree; } /* * Update the maximum field-width information in `mwp' based on * the file system specified by `sfsp'. */ static void update_maxwidths(struct maxwidths *mwp, const struct statfs *sfsp) { static long blocksize = 0; int dummy; if (blocksize == 0) getbsize(&dummy, &blocksize); mwp->mntfrom = imax(mwp->mntfrom, (int)strlen(sfsp->f_mntfromname)); mwp->fstype = imax(mwp->fstype, (int)strlen(sfsp->f_fstypename)); mwp->total = imax(mwp->total, int64width( fsbtoblk((int64_t)sfsp->f_blocks, sfsp->f_bsize, blocksize))); mwp->used = imax(mwp->used, int64width(fsbtoblk((int64_t)sfsp->f_blocks - (int64_t)sfsp->f_bfree, sfsp->f_bsize, blocksize))); mwp->avail = imax(mwp->avail, int64width(fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize))); mwp->iused = imax(mwp->iused, int64width((int64_t)sfsp->f_files - sfsp->f_ffree)); mwp->ifree = imax(mwp->ifree, int64width(sfsp->f_ffree)); } /* Return the width in characters of the specified value. */ static int int64width(int64_t val) { int len; len = 0; /* Negative or zero values require one extra digit. */ if (val <= 0) { val = -val; len++; } while (val > 0) { len++; val /= 10; } return (len); } static void usage(void) { xo_error( "usage: df [-b | -g | -H | -h | -k | -m | -P] [-acilnT] [-t type] [-,]\n" " [file | filesystem ...]\n"); exit(EX_USAGE); } static char * makenetvfslist(void) { char *str, *strptr, **listptr; struct xvfsconf *xvfsp, *keep_xvfsp; size_t buflen; int cnt, i, maxvfsconf; if (sysctlbyname("vfs.conflist", NULL, &buflen, NULL, 0) < 0) { xo_warn("sysctl(vfs.conflist)"); return (NULL); } xvfsp = malloc(buflen); if (xvfsp == NULL) { xo_warnx("malloc failed"); return (NULL); } keep_xvfsp = xvfsp; if (sysctlbyname("vfs.conflist", xvfsp, &buflen, NULL, 0) < 0) { xo_warn("sysctl(vfs.conflist)"); free(keep_xvfsp); return (NULL); } maxvfsconf = buflen / sizeof(struct xvfsconf); if ((listptr = malloc(sizeof(char*) * maxvfsconf)) == NULL) { xo_warnx("malloc failed"); free(keep_xvfsp); return (NULL); } for (cnt = 0, i = 0; i < maxvfsconf; i++) { if (xvfsp->vfc_flags & VFCF_NETWORK) { listptr[cnt++] = strdup(xvfsp->vfc_name); if (listptr[cnt-1] == NULL) { xo_warnx("malloc failed"); free(listptr); free(keep_xvfsp); return (NULL); } } xvfsp++; } if (cnt == 0 || (str = malloc(sizeof(char) * (32 * cnt + cnt + 2))) == NULL) { if (cnt > 0) xo_warnx("malloc failed"); free(listptr); free(keep_xvfsp); return (NULL); } *str = 'n'; *(str + 1) = 'o'; for (i = 0, strptr = str + 2; i < cnt; i++, strptr++) { strlcpy(strptr, listptr[i], 32); strptr += strlen(listptr[i]); *strptr = ','; free(listptr[i]); } *(--strptr) = '\0'; free(keep_xvfsp); free(listptr); return (str); }