du(1): Add --si option to display in terms of powers of 1000

Reviewed by:	cem (earlier version), emaste
Approved by:	emaste (mentor)
Differential Revision:	https://reviews.freebsd.org/D11748
This commit is contained in:
Kyle Evans 2017-08-09 01:19:19 +00:00
parent 1070a9141c
commit 476c601b7a
3 changed files with 60 additions and 21 deletions

View File

@ -28,7 +28,7 @@
.\" @(#)du.1 8.2 (Berkeley) 4/1/94 .\" @(#)du.1 8.2 (Berkeley) 4/1/94
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd November 4, 2012 .Dd August 8, 2017
.Dt DU 1 .Dt DU 1
.Os .Os
.Sh NAME .Sh NAME
@ -63,9 +63,10 @@ Calculate block counts in
.Ar blocksize .Ar blocksize
byte blocks. byte blocks.
This is different from the This is different from the
.Fl h, k, m .Fl h, k, m,
.Fl Fl si
and and
.Fl g .Fl g
options or setting options or setting
.Ev BLOCKSIZE .Ev BLOCKSIZE
and gives an estimate of how much space the examined file hierarchy would and gives an estimate of how much space the examined file hierarchy would
@ -101,7 +102,7 @@ Display block counts in 1073741824-byte (1 GiB) blocks.
.Dq Human-readable .Dq Human-readable
output. output.
Use unit suffixes: Byte, Kilobyte, Megabyte, Use unit suffixes: Byte, Kilobyte, Megabyte,
Gigabyte, Terabyte and Petabyte. Gigabyte, Terabyte and Petabyte based on powers of 1024.
.It Fl k .It Fl k
Display block counts in 1024-byte (1 kiB) blocks. Display block counts in 1024-byte (1 kiB) blocks.
.It Fl l .It Fl l
@ -131,6 +132,11 @@ This option exists solely for conformance with
Display an entry for each specified file. Display an entry for each specified file.
(Equivalent to (Equivalent to
.Fl d Li 0 ) .Fl d Li 0 )
.It Fl Fl si
.Dq Human-readable
output.
Use unit suffixes: Byte, Kilobyte, Megabyte,
Gigabyte, Terabyte and Petabyte based on powers of 1000.
.It Fl t Ar threshold .It Fl t Ar threshold
Display only entries for which size exceeds Display only entries for which size exceeds
.Ar threshold . .Ar threshold .
@ -166,9 +172,9 @@ options override each other and the command's actions are determined
by the last one specified. by the last one specified.
.Pp .Pp
The The
.Fl h, k .Fl h, k, m
and and
.Fl m .Fl Fl si
options all override each other; the last one specified determines options all override each other; the last one specified determines
the block counts used. the block counts used.
.Sh ENVIRONMENT .Sh ENVIRONMENT
@ -177,17 +183,17 @@ the block counts used.
If the environment variable If the environment variable
.Ev BLOCKSIZE .Ev BLOCKSIZE
is set, and the is set, and the
.Fl h, k .Fl h, k, m
or or
.Fl m .Fl Fl si
options are not specified, the block counts will be displayed in units of options are not specified, the block counts will be displayed in units of
that block size. that block size.
If If
.Ev BLOCKSIZE .Ev BLOCKSIZE
is not set, and the is not set, and the
.Fl h, k .Fl h, k, m
or or
.Fl m .Fl Fl si
options are not specified, the block counts will be displayed in 512-byte options are not specified, the block counts will be displayed in 512-byte
blocks. blocks.
.El .El

View File

@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <errno.h> #include <errno.h>
#include <fnmatch.h> #include <fnmatch.h>
#include <fts.h> #include <fts.h>
#include <getopt.h>
#include <libutil.h> #include <libutil.h>
#include <locale.h> #include <locale.h>
#include <stdint.h> #include <stdint.h>
@ -60,6 +61,11 @@ __FBSDID("$FreeBSD$");
#include <sysexits.h> #include <sysexits.h>
#include <unistd.h> #include <unistd.h>
#define SI_OPT (CHAR_MAX + 1)
#define UNITS_2 1
#define UNITS_SI 2
static SLIST_HEAD(ignhead, ignentry) ignores; static SLIST_HEAD(ignhead, ignentry) ignores;
struct ignentry { struct ignentry {
char *mask; char *mask;
@ -75,10 +81,16 @@ static int ignorep(FTSENT *);
static void siginfo(int __unused); static void siginfo(int __unused);
static int nodumpflag = 0; static int nodumpflag = 0;
static int Aflag; static int Aflag, hflag;
static long blocksize, cblocksize; static long blocksize, cblocksize;
static volatile sig_atomic_t info; static volatile sig_atomic_t info;
static const struct option long_options[] =
{
{ "si", no_argument, NULL, SI_OPT },
{ NULL, no_argument, NULL, 0 },
};
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
@ -89,14 +101,13 @@ main(int argc, char *argv[])
int ftsoptions; int ftsoptions;
int depth; int depth;
int Hflag, Lflag, aflag, sflag, dflag, cflag; int Hflag, Lflag, aflag, sflag, dflag, cflag;
int hflag, lflag, ch, notused, rval; int lflag, ch, notused, rval;
char **save; char **save;
static char dot[] = "."; static char dot[] = ".";
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
Hflag = Lflag = aflag = sflag = dflag = cflag = hflag = Hflag = Lflag = aflag = sflag = dflag = cflag = lflag = Aflag = 0;
lflag = Aflag = 0;
save = argv; save = argv;
ftsoptions = FTS_PHYSICAL; ftsoptions = FTS_PHYSICAL;
@ -108,7 +119,8 @@ main(int argc, char *argv[])
depth = INT_MAX; depth = INT_MAX;
SLIST_INIT(&ignores); SLIST_INIT(&ignores);
while ((ch = getopt(argc, argv, "AB:HI:LPasd:cghklmnrt:x")) != -1) while ((ch = getopt_long(argc, argv, "+AB:HI:LPasd:cghklmnrt:x",
long_options, NULL)) != -1)
switch (ch) { switch (ch) {
case 'A': case 'A':
Aflag = 1; Aflag = 1;
@ -160,7 +172,7 @@ main(int argc, char *argv[])
blocksize = 1073741824; blocksize = 1073741824;
break; break;
case 'h': case 'h':
hflag = 1; hflag = UNITS_2;
break; break;
case 'k': case 'k':
hflag = 0; hflag = 0;
@ -189,6 +201,9 @@ main(int argc, char *argv[])
case 'x': case 'x':
ftsoptions |= FTS_XDEV; ftsoptions |= FTS_XDEV;
break; break;
case SI_OPT:
hflag = UNITS_SI;
break;
case '?': case '?':
default: default:
usage(); usage();
@ -270,7 +285,7 @@ main(int argc, char *argv[])
if (p->fts_level <= depth && threshold <= if (p->fts_level <= depth && threshold <=
threshold_sign * howmany(p->fts_bignum * threshold_sign * howmany(p->fts_bignum *
cblocksize, blocksize)) { cblocksize, blocksize)) {
if (hflag) { if (hflag > 0) {
prthumanval(p->fts_bignum); prthumanval(p->fts_bignum);
(void)printf("\t%s\n", p->fts_path); (void)printf("\t%s\n", p->fts_path);
} else { } else {
@ -306,7 +321,7 @@ main(int argc, char *argv[])
howmany(p->fts_statp->st_blocks, cblocksize); howmany(p->fts_statp->st_blocks, cblocksize);
if (aflag || p->fts_level == 0) { if (aflag || p->fts_level == 0) {
if (hflag) { if (hflag > 0) {
prthumanval(curblocks); prthumanval(curblocks);
(void)printf("\t%s\n", p->fts_path); (void)printf("\t%s\n", p->fts_path);
} else { } else {
@ -326,7 +341,7 @@ main(int argc, char *argv[])
err(1, "fts_read"); err(1, "fts_read");
if (cflag) { if (cflag) {
if (hflag) { if (hflag > 0) {
prthumanval(savednumber); prthumanval(savednumber);
(void)printf("\ttotal\n"); (void)printf("\ttotal\n");
} else { } else {
@ -474,13 +489,16 @@ static void
prthumanval(int64_t bytes) prthumanval(int64_t bytes)
{ {
char buf[5]; char buf[5];
int flags;
bytes *= cblocksize; bytes *= cblocksize;
flags = HN_B | HN_NOSPACE | HN_DECIMAL;
if (!Aflag) if (!Aflag)
bytes *= DEV_BSIZE; bytes *= DEV_BSIZE;
if (hflag == UNITS_SI)
flags |= HN_DIVISOR_1000;
humanize_number(buf, sizeof(buf), bytes, "", HN_AUTOSCALE, humanize_number(buf, sizeof(buf), bytes, "", HN_AUTOSCALE, flags);
HN_B | HN_NOSPACE | HN_DECIMAL);
(void)printf("%4s", buf); (void)printf("%4s", buf);
} }

View File

@ -141,6 +141,20 @@ m_flag_body()
atf_check -o inline:'1\tA\n1\tB\n1024\tC\n' du -Am A B C atf_check -o inline:'1\tA\n1\tB\n1024\tC\n' du -Am A B C
} }
atf_test_case si_flag
si_flag_head()
{
atf_set "descr" "Verify --si output"
}
si_flag_body()
{
atf_check truncate -s 1500000 A
atf_check truncate -s 1572864 B
atf_check -o inline:'1.4M\tA\n1.5M\tB\n' du -Ah A B
atf_check -o inline:'1.5M\tA\n1.6M\tB\n' du -A --si A B
}
atf_init_test_cases() atf_init_test_cases()
{ {
atf_add_test_case A_flag atf_add_test_case A_flag
@ -150,4 +164,5 @@ atf_init_test_cases()
atf_add_test_case h_flag atf_add_test_case h_flag
atf_add_test_case k_flag atf_add_test_case k_flag
atf_add_test_case m_flag atf_add_test_case m_flag
atf_add_test_case si_flag
} }