summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-05-19 07:33:29 -0500
committerKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-05-19 07:33:29 -0500
commitd4262d57368f86161a4cf5175180039a806612a0 (patch)
treefc11e03d60a349538a2407f38de343387dcd75d6 /bin
parent5fa3142cdbb67cbb8287b2ec4fc35ee6532b3c6d (diff)
downloaduserland-d4262d57368f86161a4cf5175180039a806612a0.tar.gz
userland-d4262d57368f86161a4cf5175180039a806612a0.tar.bz2
userland-d4262d57368f86161a4cf5175180039a806612a0.tar.xz
userland-d4262d57368f86161a4cf5175180039a806612a0.zip
bin/df: rewrite
Diffstat (limited to 'bin')
-rw-r--r--bin/df/df.1175
-rw-r--r--bin/df/df.c832
2 files changed, 383 insertions, 624 deletions
diff --git a/bin/df/df.1 b/bin/df/df.1
index 6ac5ed0..3cc44db 100644
--- a/bin/df/df.1
+++ b/bin/df/df.1
@@ -2,6 +2,8 @@
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 2019
+.\" Adélie Userland Team. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -37,9 +39,8 @@
.Nd display free disk space
.Sh SYNOPSIS
.Nm
-.Op Fl agln
-.Op Fl Ghkm | Fl ihkm | Fl Pk
-.Op Fl t Ar type
+.Op Fl hks | Fl Pk
+.Op Fl t
.Op Ar file | Ar file_system ...
.Sh DESCRIPTION
.Nm
@@ -54,153 +55,69 @@ If neither a file or a
operand is specified,
statistics for all mounted file systems are displayed
(subject to the
-.Fl l
-and
.Fl t
-options below).
-.Pp
-Note that the printed count of available blocks takes
-.Va minfree
-into account, and thus will be negative when the number of free blocks
-on the filesystem is less than
-.Va minfree .
+option below).
.Pp
The following options are available:
.Bl -tag -width Ds
-.It Fl a
-Show all mount points,
-including those that were mounted with the
-.Dv MNT_IGNORE
-flag.
-.It Fl G
-Display all the fields of the structure(s) returned by
-.Xr statvfs 2 .
-This option cannot be used with the
-.Fl i
-or
-.Fl P
-options, and it is modelled after the Solaris
-.Fl g
-option.
-This option will override the
-.Fl g ,
-.Fl h ,
-.Fl k ,
-and
-.Fl m
-options, as well as any setting of
-.Ev BLOCKSIZE .
-.It Fl g
-The
-.Fl g
-option causes the numbers to be reported in gigabytes (1024*1024*1024
-bytes).
.It Fl h
"Human-readable" output.
-Use unit suffixes: Byte, Kilobyte, Megabyte,
-Gigabyte, Terabyte, Petabyte, Exabyte in order to reduce the number of
-digits to four or less.
-.It Fl i
-Include statistics on the number of free inodes.
+Use powers of 1024 to reduce the number of digits to four or less, via
+the IEEE prefixes (byte, kibibyte, mebibyte, and so on). This option
+conflicts with the
+.Fl k
+and
+.Fl s
+options.
.It Fl k
By default, all sizes are reported in 512-byte block counts.
The
.Fl k
option causes the numbers to be reported in kilobytes (1024 bytes).
-.It Fl l
-Display statistics only about mounted file systems with the
-.Dv MNT_LOCAL
-flag set.
-If a non-local file system is given as an argument, a
-warning is issued and no information is given on that file system.
-.It Fl m
-The
-.Fl m
-option causes the numbers to be reported in megabytes (1024*1024 bytes).
-.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
-Produce output in the following portable format:
-.Pp
-If both the
-.Fl P
+This option conflicts with the
+.Fl h
and
-.Fl k
-option are specified, the output will be preceded by the following header
-line, formatted to match the data following it:
-.Bd -literal
-"Filesystem 1024-blocks Used Available Capacity Mounted on\en"
-.Ed
-.Pp
-If the
-.Fl P
-option is specified without the
-.Fl k
-options, the output will be preceded by the following header line,
-formatted to match the data following it:
-.Bd -literal
-"Filesystem <blksize>-blocks Used Available Capacity Mounted on\en"
-.Ed
-.Pp
-The header line is followed by data formatted as follows:
+.Fl s
+options.
+.It Fl P
+Produce POSIX-compliant output, which is described as the following:
.Bd -literal
+"Filesystem <blksize>-blocks Used Available Capacity Mounted On\en"
"%s %d %d %d %d%% %s\en", <file system name>, <total space>,
<space used>, <space free>, <percentage used>,
<file system root>
.Ed
-.Pp
-Note that the
-.Fl i
-option may not be specified with
-.Fl P .
-.It Fl t Ar type
-Is used to indicate the actions should only be taken on
-filesystems of the specified type.
-More than one type may be specified in a comma-separated list.
-The list of filesystem types can be prefixed with
-.Dq no
-to specify the filesystem types for which action should
-.Em not
-be taken.
-If a file system is given on the command line that is not of
-the specified type, a warning is issued and no information is given on
-that file system.
-.El
-.Sh ENVIRONMENT
-.Bl -tag -width BLOCKSIZE
-.It Ev BLOCKSIZE
-If the environment variable
-.Ev BLOCKSIZE
-is set, and the
-.Fl g ,
-.Fl h ,
+Note that 'blksize' is 512 by default, and may be changed to 1024 via
+the
.Fl k
+option. No other options may be specified alongside the
+.Fl P
+option.
+.It Fl s
+"Human readable" output.
+Use SI units (powers of 1000) to reduce the number of digits to four
+or less (byte, kilobyte, megabyte, and so on). This option conflicts
+with the
+.Fl h
and
-.Fl m
-options are not specified, the block counts will be displayed in units of that
-size block.
+.Fl k
+options.
+.It Fl t
+Show the type of the filesystems listed. This option cannot be used
+with the
+.Fl P
+option.
.El
+.Sh CONFORMANCE
+This implementation of
+.Nm
+is fully conformant with POSIX.1-2017, with two extensions inspired by
+GNU coreutils.
.Sh SEE ALSO
-.Xr quota 1 ,
.Xr fstatvfs 2 ,
-.Xr getvfsstat 2 ,
+.Xr mount 2 ,
.Xr statvfs 2 ,
-.Xr getbsize 3 ,
-.Xr getmntinfo 3 ,
+.Xr setmntent 3 ,
+.Xr getmntent 3 ,
.Xr fs 5 ,
-.Xr fstab 5 ,
-.Xr mount 8 ,
-.Xr quot 8 ,
-.Xr tunefs 8
-.Sh HISTORY
-A
-.Nm
-utility appeared in
-.At v1 .
+.Xr fstab 5
diff --git a/bin/df/df.c b/bin/df/df.c
index 9392d0c..1cde1c8 100644
--- a/bin/df/df.c
+++ b/bin/df/df.c
@@ -1,520 +1,362 @@
-/* $NetBSD: df.c,v 1.93 2018/08/26 23:34:52 sevan Exp $ */
-
/*
- * 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.
- *
+ * Copyright (c) 2019 Adélie Userland Team. All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * 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.
+ * 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.
+ * 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * HOLDER 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.
*/
+#include <sys/statvfs.h>
-#include <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT(
-"@(#) Copyright (c) 1980, 1990, 1993, 1994\
- The Regents of the University of California. All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)df.c 8.7 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: df.c,v 1.93 2018/08/26 23:34:52 sevan Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
+#include <bsd/stdlib.h>
-#include <assert.h>
-#include <err.h>
#include <errno.h>
-#include <fcntl.h>
#include <locale.h>
-#include <util.h>
+#include <math.h>
+#include <mntent.h>
+#include <stdbool.h>
#include <stdio.h>
-#include <stdlib.h>
+#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include <unistd.h>
-#include <util.h>
-
-static char *getmntpt(const char *);
-static void prtstat(struct statvfs *, int);
-static int selected(const char *, size_t);
-static void maketypelist(char *);
-static size_t regetmntinfo(struct statvfs **, size_t);
-__dead static void usage(void);
-static void prthumanval(int64_t, const char *);
-static void prthuman(struct statvfs *, int64_t, int64_t);
-
-static int aflag, gflag, hflag, iflag, lflag, nflag, Pflag;
-static long usize;
-static char **typelist;
-
-int
-main(int argc, char *argv[])
-{
- struct stat stbuf;
- struct statvfs *mntbuf;
- long mntsize;
- int ch, i, maxwidth, width;
- char *mntpt;
-
- setprogname(argv[0]);
- (void)setlocale(LC_ALL, "");
-
- while ((ch = getopt(argc, argv, "aGghiklmnPt:")) != -1)
- switch (ch) {
- case 'a':
- aflag = 1;
- break;
- case 'g':
- hflag = 0;
- usize = 1024 * 1024 * 1024;
- break;
- case 'G':
- gflag = 1;
- break;
- case 'h':
- hflag = 1;
- usize = 0;
- break;
- case 'i':
- iflag = 1;
- break;
- case 'k':
- hflag = 0;
- usize = 1024;
- break;
- case 'l':
- lflag = 1;
- break;
- case 'm':
- hflag = 0;
- usize = 1024 * 1024;
- break;
- case 'n':
- nflag = 1;
- break;
- case 'P':
- Pflag = 1;
- break;
- case 't':
- if (typelist != NULL)
- errx(EXIT_FAILURE,
- "only one -t option may be specified.");
- maketypelist(optarg);
- break;
- case '?':
- default:
- usage();
- }
-
- if (gflag && (Pflag || iflag))
- errx(EXIT_FAILURE,
- "only one of -G and -P or -i may be specified");
- if (Pflag && iflag)
- errx(EXIT_FAILURE,
- "only one of -P and -i may be specified");
-#if 0
- /*
- * The block size cannot be checked until after getbsize() is called.
- */
- if (Pflag && (hflag || (usize != 1024 && usize != 512)))
- errx(EXIT_FAILURE,
- "non-standard block size incompatible with -P");
-#endif
- argc -= optind;
- argv += optind;
-
- mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
- if (mntsize == 0)
- err(EXIT_FAILURE,
- "retrieving information on mounted file systems");
- if (*argv == NULL) {
- mntsize = regetmntinfo(&mntbuf, mntsize);
- } else {
- if ((mntbuf = malloc(argc * sizeof(*mntbuf))) == NULL)
- err(EXIT_FAILURE, "can't allocate statvfs array");
- mntsize = 0;
- for (/*EMPTY*/; *argv != NULL; argv++) {
- if (stat(*argv, &stbuf) < 0) {
- if ((mntpt = getmntpt(*argv)) == 0) {
- warn("%s", *argv);
- continue;
- }
- } else if (S_ISBLK(stbuf.st_mode)) {
- if ((mntpt = getmntpt(*argv)) == 0)
- mntpt = *argv;
- } else
- mntpt = *argv;
- /*
- * Statfs does not take a `wait' flag, so we cannot
- * implement nflag here.
- */
- if (!statvfs(mntpt, &mntbuf[mntsize]))
- if (lflag &&
- (mntbuf[mntsize].f_flag & MNT_LOCAL) == 0)
- warnx("Warning: %s is not a local %s",
- *argv, "file system");
- else if
- (!selected(mntbuf[mntsize].f_fstypename,
- sizeof(mntbuf[mntsize].f_fstypename)))
- warnx("Warning: %s mounted as a %s %s",
- *argv,
- mntbuf[mntsize].f_fstypename,
- "file system");
- else
- ++mntsize;
- else
- warn("%s", *argv);
- }
- }
-
- maxwidth = 0;
- for (i = 0; i < mntsize; i++) {
- width = (int)strlen(mntbuf[i].f_mntfromname);
- if (width > maxwidth)
- maxwidth = width;
- }
- for (i = 0; i < mntsize; i++)
- prtstat(&mntbuf[i], maxwidth);
- return 0;
-}
-
-static char *
-getmntpt(const char *name)
-{
- size_t mntsize, i;
- struct statvfs *mntbuf;
-
- mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
- if (mntsize == 0)
- err(EXIT_FAILURE, "Can't get mount information");
- for (i = 0; i < mntsize; i++) {
- if (!strcmp(mntbuf[i].f_mntfromname, name))
- return mntbuf[i].f_mntonname;
- }
- return 0;
-}
-
-static enum { IN_LIST, NOT_IN_LIST } which;
-
-static int
-selected(const char *type, size_t len)
-{
- char **av;
-
- /* If no type specified, it's always selected. */
- if (typelist == NULL)
- return 1;
- for (av = typelist; *av != NULL; ++av)
- if (!strncmp(type, *av, len))
- return which == IN_LIST ? 1 : 0;
- return which == IN_LIST ? 0 : 1;
+static void usage(void);
+char *humanize(uint64_t size, bool si);
+
+static bool hflag, kflag, Pflag, tflag, sflag, restricted;
+
+struct fs {
+ char *device;
+ char *mount;
+ char *type;
+ char *total;
+ char *used;
+ char *avail;
+ char *percent;
+ unsigned long fsid;
+ bool print;
+ struct fs *next;
+};
+
+struct fs *fs_create(void) {
+ struct fs *node = malloc(sizeof(struct fs));
+ node->next = NULL;
+ return node;
}
-static void
-maketypelist(char *fslist)
-{
- size_t i;
- char *nextcp, **av;
-
- if ((fslist == NULL) || (fslist[0] == '\0'))
- errx(EXIT_FAILURE, "empty type list");
-
- /*
- * XXX
- * Note: the syntax is "noxxx,yyy" for no xxx's and
- * no yyy's, not the more intuitive "noyyy,noyyy".
- */
- if (fslist[0] == 'n' && fslist[1] == 'o') {
- fslist += 2;
- which = NOT_IN_LIST;
- } else
- which = IN_LIST;
-
- /* Count the number of types. */
- for (i = 1, nextcp = fslist;
- (nextcp = strchr(nextcp, ',')) != NULL; i++)
- ++nextcp;
-
- /* Build an array of that many types. */
- if ((av = typelist = malloc((i + 1) * sizeof(*av))) == NULL)
- err(EXIT_FAILURE, "can't allocate type array");
- av[0] = fslist;
- for (i = 1, nextcp = fslist;
- (nextcp = strchr(nextcp, ',')) != NULL; i++) {
- *nextcp = '\0';
- av[i] = ++nextcp;
- }
- /* Terminate the array. */
- av[i] = NULL;
+struct fs *fs_add(struct fs *root, const char *device, const char *mount,
+ const char *type, const char total[21], const char used[21],
+ const char avail[21], double percent, unsigned long fsid) {
+ struct fs *node = fs_create();
+ char temp[5];
+
+ node->device = strndup(device, 24);
+ node->total = strndup(total, 20);
+ node->used = strndup(used, 20);
+ node->avail = strndup(avail, 20);
+ node->mount = strndup(mount, 64);
+ node->type = strndup(type, 10);
+ snprintf(temp, 5, "%.0f%%", percent);
+ node->percent = strndup(temp, 5);
+ node->fsid = fsid;
+ node->print = false;
+
+ if (root == NULL) {
+ return node;
+ } else if (root->next == NULL) {
+ root->next = node;
+ return root;
+ } else {
+ struct fs *temp = root;
+ while (temp != NULL) {
+ if (temp->next == NULL) {
+ temp->next = node;
+ return root;
+ }
+ temp = temp->next;
+ }
+ }
}
-/*
- * Make a pass over the filesystem info in ``mntbuf'' filtering out
- * filesystem types not in ``fsmask'' and possibly re-stating to get
- * current (not cached) info. Returns the new count of valid statvfs bufs.
- */
-static size_t
-regetmntinfo(struct statvfs **mntbufp, size_t mntsize)
-{
- size_t i, j;
- struct statvfs *mntbuf;
-
- if (!lflag && typelist == NULL && aflag)
- return nflag ? mntsize : (size_t)getmntinfo(mntbufp, MNT_WAIT);
-
- mntbuf = *mntbufp;
- j = 0;
- for (i = 0; i < mntsize; i++) {
- if (!aflag && (mntbuf[i].f_flag & MNT_IGNORE) != 0)
- continue;
- if (lflag && (mntbuf[i].f_flag & MNT_LOCAL) == 0)
- continue;
- if (!selected(mntbuf[i].f_fstypename,
- sizeof(mntbuf[i].f_fstypename)))
- continue;
- if (nflag)
- mntbuf[j] = mntbuf[i];
- else {
- struct statvfs layerbuf = mntbuf[i];
- (void)statvfs(mntbuf[i].f_mntonname, &mntbuf[j]);
- /*
- * If the FS name changed, then new data is for
- * a different layer and we don't want it.
- */
- if (memcmp(layerbuf.f_mntfromname,
- mntbuf[j].f_mntfromname, MNAMELEN))
- mntbuf[j] = layerbuf;
- }
- j++;
- }
- return j;
+int8_t longest[5];
+#define R_FSNAME 0
+#define R_TOTAL 1
+#define R_USED 2
+#define R_AVAIL 3
+#define R_FSTYPE 4
+#define R_MAX 5
+struct fs *fs_build(struct fs *root, int unit) {
+ struct statvfs stv;
+ FILE *mnt;
+ struct mntent *ment;
+
+ for (uint_fast8_t i = 0; i < R_MAX; i++) {
+ longest[i] = -1;
+ }
+
+ mnt = setmntent("/etc/mtab", "r");
+ while ((ment = getmntent(mnt)) != NULL) {
+ if (statvfs(ment->mnt_dir, &stv) != 0) {
+ char *error = strerror(errno);
+ fprintf(stderr, "statvfs(): unable to read %s: %s\n",
+ ment->mnt_dir, error);
+ continue;
+ }
+ if (stv.f_blocks == 0) {
+ continue;
+ }
+ int8_t current[5], spacelen = -1;
+ char totals[21], useds[21], avails[21];
+ for (uint_fast8_t i = 0; i < R_MAX; i++) {
+ current[i] = -1;
+ }
+ uint64_t used = (stv.f_blocks - stv.f_bfree) * stv.f_frsize;
+ uint64_t total = stv.f_blocks * stv.f_frsize;
+ uint64_t avail = stv.f_bavail * stv.f_frsize;
+ double percent = 100 * used / (double)total;
+
+ if (hflag || sflag) {
+ spacelen = 8;
+ snprintf(totals, 8, "%s", humanize(total, sflag));
+ snprintf(useds, 8, "%s", humanize(used, sflag));
+ snprintf(avails, 8, "%s", humanize(avail, sflag));
+ } else {
+ spacelen = 21;
+ snprintf(totals, 21, "%ld", total / unit);
+ snprintf(useds, 21, "%ld", used / unit);
+ snprintf(avails, 21, "%ld", avail / unit);
+ }
+ current[R_FSNAME] = strnlen(ment->mnt_fsname, 24);
+ current[R_FSTYPE] = strnlen(ment->mnt_type, 10);
+ current[R_TOTAL] = strnlen(totals, spacelen);
+ current[R_USED] = strnlen(useds, spacelen);
+ current[R_AVAIL] = strnlen(avails, spacelen);
+
+ for (uint_fast8_t i = 0; i < R_MAX; i++) {
+ if (longest[i] < current[i]) {
+ longest[i] = current[i];
+ }
+ }
+
+ root = fs_add(root, ment->mnt_fsname, ment->mnt_dir, ment->mnt_type,
+ totals, useds, avails, percent, stv.f_fsid);
+ }
+ endmntent(mnt);
+
+ return root;
}
-
-static void
-prthumanval(int64_t bytes, const char *pad)
-{
- char buf[6];
-
- (void)humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1),
- bytes, "", HN_AUTOSCALE,
- HN_B | HN_NOSPACE | HN_DECIMAL);
-
- (void)printf("%s %6s", pad, buf);
+void fs_filter(struct fs *root, int argc, char **argv) {
+ struct statvfs stv;
+ for (uint_fast16_t i = 0; i < argc; i++) {
+ struct fs *temp = root;
+ if (statvfs(argv[i], &stv) != 0) {
+ char *error = strerror(errno);
+ fprintf(stderr, "statvfs(): unable to read %s: %s\n",
+ argv[i], error);
+ continue;
+ }
+ while (temp != NULL) {
+ if (temp->fsid == stv.f_fsid) {
+ temp->print = true;
+ break;
+ }
+ temp = temp->next;
+ }
+ }
}
-static void
-prthuman(struct statvfs *sfsp, int64_t used, int64_t bavail)
-{
-
- prthumanval((int64_t)(sfsp->f_blocks * sfsp->f_frsize), " ");
- prthumanval((int64_t)(used * sfsp->f_frsize), " ");
- prthumanval((int64_t)(bavail * sfsp->f_frsize), " ");
+int
+main(int argc, char **argv) {
+ int ch, unit = 512;
+ struct fs *root = NULL;
+ hflag = kflag = Pflag = tflag = sflag = restricted = false;
+ char *header = "Filesystem %d-blocks Used Avail Capacity Mounted on\n";
+ char *fmt = "%s %s %s %s %s %s\n";
+ int buflen = -1;
+
+ setprogname(argv[0]);
+ (void)setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "hksPt")) != -1) {
+ switch(ch) {
+ case 'h':
+ if (kflag || sflag) {
+ fprintf(stderr,
+ "%s: -h, -s, and -k cannot be used together.\n",
+ getprogname());
+ usage();
+ }
+ hflag = true;
+ unit = -1;
+ break;
+ case 'k':
+ if (hflag || sflag) {
+ fprintf(stderr,
+ "%s: -h, -s, and -k cannot be used together.\n",
+ getprogname());
+ usage();
+ }
+ kflag = true;
+ unit = 1024;
+ break;
+ case 'P':
+ if (tflag) {
+ fprintf(stderr, "%s: Cannot output types in POSIX mode.\n",
+ getprogname());
+ usage();
+ }
+ Pflag = true;
+ break;
+ case 's':
+ if (kflag || hflag) {
+ fprintf(stderr,
+ "%s: -h, -s, and -k cannot be used together.\n",
+ getprogname());
+ usage();
+ }
+ sflag = true;
+ unit = -1;
+ break;
+ case 't':
+ if (Pflag) {
+ fprintf(stderr, "%s: Cannot output types in POSIX mode.\n",
+ getprogname());
+ usage();
+ }
+ tflag = true;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argv[0] != NULL) {
+ /* only get information on filesystems containing the listed files */
+ restricted = true;
+ }
+
+ root = fs_build(root, unit);
+
+ if (restricted) {
+ printf("restrict\n");
+ fs_filter(root, argc, argv);
+ }
+ if (!Pflag) {
+ for (uint_fast8_t i = 0; i < R_MAX; i++) {
+ buflen += longest[i] + 1;
+ }
+ if (!tflag) {
+ buflen -= longest[R_FSTYPE] + 1;
+ }
+ } else {
+ buflen = strlen(fmt);
+ }
+ char temp[buflen + 1];
+ if (!Pflag) {
+ if (tflag) {
+ snprintf(temp, buflen,
+ "%%-%ds %%%ds %%%ds %%%ds %%4s %%-%ds %%s\n",
+ longest[R_FSNAME], longest[R_TOTAL], longest[R_USED],
+ longest[R_AVAIL], longest[R_FSTYPE]);
+ } else {
+ snprintf(temp, buflen,
+ "%%-%ds %%%ds %%%ds %%%ds %%4s %%s\n",
+ longest[R_FSNAME], longest[R_TOTAL], longest[R_USED],
+ longest[R_AVAIL]);
+ }
+ } else {
+ snprintf(temp, buflen, "%s", fmt);
+ }
+ if (Pflag) {
+ printf("Filesystem %d-blocks Used Avail Capacity Mounted on\n", unit);
+ } else if (tflag) {
+ printf(temp, "Filesystem", "Total", "Used", "Avail", "Use%", "Type",
+ "Mounted on");
+ } else {
+ printf(temp, "Filesystem", "Total", "Used", "Avail", "Use%",
+ "Mounted on");
+ }
+ while (root != NULL) {
+ if ((restricted && root->print) || !restricted) {
+ if (Pflag) {
+ printf("%s %s %s %s %s %s\n", root->device, root->total, root->used, root->avail,
+ root->percent, root->mount);
+ } else if (tflag) {
+ printf(temp, root->device, root->total, root->used, root->avail,
+ root->percent, root->type, root->mount);
+ } else {
+ printf(temp, root->device, root->total, root->used, root->avail,
+ root->percent, root->mount);
+ }
+ }
+ root = root->next;
+ }
+ return EXIT_SUCCESS;
}
-/*
- * Convert statvfs returned filesystem size into BLOCKSIZE units.
- * Attempts to avoid overflow for large filesystems.
- */
-#define fsbtoblk(num, fsbs, bs) \
- (((fsbs) != 0 && (uint64_t)(fsbs) < (uint64_t)(bs)) ? \
- (int64_t)(num) / (int64_t)((bs) / (fsbs)) : \
- (int64_t)(num) * (int64_t)((fsbs) / (bs)))
-
-/*
- * Print out status about a filesystem.
- */
-static void
-prtstat(struct statvfs *sfsp, int maxwidth)
-{
- static long blocksize;
- static int headerlen, timesthrough;
- static const char *header;
- static const char full[] = "100";
- static const char empty[] = " 0";
- int64_t used, availblks, inodes;
- int64_t bavail;
- char pb[64];
-
- if (gflag) {
- /*
- * From SunOS-5.6:
- *
- * /var (/dev/dsk/c0t0d0s3 ): 8192 block size 1024 frag size
- * 984242 total blocks 860692 free blocks 859708 available 249984 total files
- * 248691 free files 8388611 filesys id
- * ufs fstype 0x00000004 flag 255 filename length
- *
- */
- (void)printf("%10s (%-12s): %7ld block size %12ld frag size\n",
- sfsp->f_mntonname, sfsp->f_mntfromname,
- sfsp->f_bsize, /* On UFS/FFS systems this is
- * also called the "optimal
- * transfer block size" but it
- * is of course the file
- * system's block size too.
- */
- sfsp->f_frsize); /* not so surprisingly the
- * "fundamental file system
- * block size" is the frag
- * size.
- */
- (void)printf("%10" PRId64 " total blocks %10" PRId64
- " free blocks %10" PRId64 " available\n",
- (uint64_t)sfsp->f_blocks, (uint64_t)sfsp->f_bfree,
- (uint64_t)sfsp->f_bavail);
- (void)printf("%10" PRId64 " total files %10" PRId64
- " free files %12lx filesys id\n",
- (uint64_t)sfsp->f_ffree, (uint64_t)sfsp->f_files,
- sfsp->f_fsid);
- (void)printf("%10s fstype %#15lx flag %17ld filename "
- "length\n", sfsp->f_fstypename, sfsp->f_flag,
- sfsp->f_namemax);
- (void)printf("%10lu owner %17" PRId64 " syncwrites %12" PRId64
- " asyncwrites\n\n", (unsigned long)sfsp->f_owner,
- sfsp->f_syncwrites, sfsp->f_asyncwrites);
-
- /*
- * a concession by the structured programming police to the
- * indentation police....
- */
- return;
- }
- if (maxwidth < 12)
- maxwidth = 12;
- if (++timesthrough == 1) {
- switch (blocksize = usize) {
- case 1024:
- header = Pflag ? "1024-blocks" : "1K-blocks";
- headerlen = (int)strlen(header);
- break;
- case 1024 * 1024:
- header = "1M-blocks";
- headerlen = (int)strlen(header);
- break;
- case 1024 * 1024 * 1024:
- header = "1G-blocks";
- headerlen = (int)strlen(header);
- break;
- default:
- if (hflag) {
- header = "Size";
- headerlen = (int)strlen(header);
- } else
- header = getbsize(&headerlen, &blocksize);
- break;
- }
- if (Pflag) {
- /*
- * either:
- * "Filesystem 1024-blocks Used Available Capacity Mounted on\n"
- * or:
- * "Filesystem 512-blocks Used Available Capacity Mounted on\n"
- */
- if (blocksize != 1024 && blocksize != 512)
- errx(EXIT_FAILURE,
- "non-standard block size incompatible with -P");
- (void)printf("Filesystem %s Used Available Capacity "
- "Mounted on\n", header);
- } else {
- (void)printf("%-*.*s %s Used Avail %%Cap",
- maxwidth - (headerlen - 10),
- maxwidth - (headerlen - 10),
- "Filesystem", header);
- if (iflag)
- (void)printf(" iUsed iAvail %%iCap");
- (void)printf(" Mounted on\n");
- }
- }
- used = sfsp->f_blocks - sfsp->f_bfree;
- bavail = sfsp->f_bfree - sfsp->f_bresvd;
- availblks = bavail + used;
- if (Pflag) {
- assert(hflag == 0);
- assert(blocksize > 0);
- /*
- * "%s %d %d %d %s %s\n", <file system name>, <total space>,
- * <space used>, <space free>, <percentage used>,
- * <file system root>
- */
- (void)printf("%s %" PRId64 " %" PRId64 " %" PRId64 " %s%% %s\n",
- sfsp->f_mntfromname,
- fsbtoblk(sfsp->f_blocks, sfsp->f_frsize, blocksize),
- fsbtoblk(used, sfsp->f_frsize, blocksize),
- fsbtoblk(bavail, sfsp->f_frsize, blocksize),
- availblks == 0 ? full : strspct(pb, sizeof(pb), used,
- availblks, 0), sfsp->f_mntonname);
- /*
- * another concession by the structured programming police to
- * the indentation police....
- *
- * Note iflag cannot be set when Pflag is set.
- */
- return;
- }
-
- (void)printf("%-*.*s ", maxwidth, maxwidth, sfsp->f_mntfromname);
-
- if (hflag)
- prthuman(sfsp, used, bavail);
- else
- (void)printf("%10" PRId64 " %10" PRId64 " %10" PRId64,
- fsbtoblk(sfsp->f_blocks, sfsp->f_frsize, blocksize),
- fsbtoblk(used, sfsp->f_frsize, blocksize),
- fsbtoblk(bavail, sfsp->f_frsize, blocksize));
- (void)printf(" %3s%%",
- availblks == 0 ? full :
- strspct(pb, sizeof(pb), used, availblks, 0));
- if (iflag) {
- inodes = sfsp->f_files;
- used = inodes - sfsp->f_ffree;
- (void)printf(" %8jd %8jd %4s%%",
- (intmax_t)used, (intmax_t)sfsp->f_ffree,
- inodes == 0 ? (used == 0 ? empty : full) :
- strspct(pb, sizeof(pb), used, inodes, 0));
- }
- (void)printf(" %s\n", sfsp->f_mntonname);
+char *scale[] = {
+ "",
+ "k",
+ "M",
+ "G",
+ "T",
+ "P",
+ "E",
+ "Z",
+ "Y"
+};
+const uint8_t scale_end = 9;
+
+char *humanize(uint64_t size, bool si) {
+ uint16_t unit = si ? 1000 : 1024;
+ int8_t radix = (int8_t)(log(size)/log(unit));
+ char suffix[2], ret[10];
+ double val;
+ uint64_t temp = size;
+
+ if (radix > 9) {
+ radix = 9;
+ }
+
+ val = size / (double)pow(unit, radix);
+
+ snprintf(ret, 10, "%.0f%s%sB", val, scale[radix], (si || (radix == 0)) ? "" : "i");
+
+ return strndup(ret, 10);
}
-static void
-usage(void)
-{
-
- (void)fprintf(stderr,
- "Usage: %s [-agln] [-Ghkm|-ihkm|-Pk] [-t type] [file | "
- "file_system ...]\n",
- getprogname());
- exit(1);
- /* NOTREACHED */
+void usage(void) {
+ fprintf(stderr,
+ "%s: [-hkPst] [file]...\n\n"
+ "-h Traditional human-readable units (1KiB is 1024 bytes); not usable with -k -P -s\n"
+ "-k 1024-byte units; not usable with -h -s\n"
+ "-P POSIX-compliant output; not usable with -h -s -t\n"
+ "-s SI human-readable units (1KB is 1000 bytes); not usable with -h -k -P\n"
+ "-t Show filesystem type; not usable with -P\n", getprogname());
+ exit(EXIT_FAILURE);
}