From d4262d57368f86161a4cf5175180039a806612a0 Mon Sep 17 00:00:00 2001 From: Kiyoshi Aman Date: Sun, 19 May 2019 07:33:29 -0500 Subject: bin/df: rewrite --- bin/df/df.1 | 175 ++++--------- bin/df/df.c | 832 ++++++++++++++++++++++++------------------------------------ 2 files changed, 383 insertions(+), 624 deletions(-) (limited to 'bin') 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 -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 -blocks Used Available Capacity Mounted On\en" "%s %d %d %d %d%% %s\en", , , , , , .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 -#include -#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 -#include -#include +#include -#include -#include #include -#include #include -#include +#include +#include +#include #include -#include +#define _POSIX_C_SOURCE 200809L #include #include -#include - -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", , , - * , , , - * - */ - (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); } -- cgit v1.2.3-60-g2f50