Index: head/usr.bin/du/du.1 =================================================================== --- head/usr.bin/du/du.1 (revision 322290) +++ head/usr.bin/du/du.1 (revision 322291) @@ -1,222 +1,228 @@ .\" Copyright (c) 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. .\" .\" @(#)du.1 8.2 (Berkeley) 4/1/94 .\" $FreeBSD$ .\" -.Dd November 4, 2012 +.Dd August 8, 2017 .Dt DU 1 .Os .Sh NAME .Nm du .Nd display disk usage statistics .Sh SYNOPSIS .Nm .Op Fl Aclnx .Op Fl H | L | P .Op Fl g | h | k | m .Op Fl a | s | d Ar depth .Op Fl B Ar blocksize .Op Fl I Ar mask .Op Fl t Ar threshold .Op Ar .Sh DESCRIPTION The .Nm utility displays the file system block usage for each file argument and for each directory in the file hierarchy rooted in each directory argument. If no file is specified, the block usage of the hierarchy rooted in the current directory is displayed. .Pp The options are as follows: .Bl -tag -width indent .It Fl A Display the apparent size instead of the disk usage. This can be helpful when operating on compressed volumes or sparse files. .It Fl B Ar blocksize Calculate block counts in .Ar blocksize byte blocks. This is different from the -.Fl h, k, m +.Fl h, k, m, +.Fl Fl si and -.Fl g +.Fl g options or setting .Ev BLOCKSIZE and gives an estimate of how much space the examined file hierarchy would require on a filesystem with the given .Ar blocksize . Unless in .Fl A mode, .Ar blocksize is rounded up to the next multiple of 512. .It Fl H Symbolic links on the command line are followed, symbolic links in file hierarchies are not followed. .It Fl I Ar mask Ignore files and directories matching the specified .Ar mask . .It Fl L Symbolic links on the command line and in file hierarchies are followed. .It Fl P No symbolic links are followed. This is the default. .It Fl a Display an entry for each file in a file hierarchy. .It Fl c Display a grand total. .It Fl d Ar depth Display an entry for all files and directories .Ar depth directories deep. .It Fl g Display block counts in 1073741824-byte (1 GiB) blocks. .It Fl h .Dq Human-readable output. Use unit suffixes: Byte, Kilobyte, Megabyte, -Gigabyte, Terabyte and Petabyte. +Gigabyte, Terabyte and Petabyte based on powers of 1024. .It Fl k Display block counts in 1024-byte (1 kiB) blocks. .It Fl l If a file has multiple hard links, count its size multiple times. The default behavior of .Nm is to count files with multiple hard links only once. When the .Fl l option is specified, the hard link checks are disabled, and these files are counted (and displayed) as many times as they are found. .It Fl m Display block counts in 1048576-byte (1 MiB) blocks. .It Fl n Ignore files and directories with user .Dq nodump flag .Pq Dv UF_NODUMP set. .It Fl r Generate messages about directories that cannot be read, files that cannot be opened, and so on. This is the default case. This option exists solely for conformance with .St -xpg4 . .It Fl s Display an entry for each specified file. (Equivalent to .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 Display only entries for which size exceeds .Ar threshold . If .Ar threshold is negative, display only entries for which size is less than the absolute value of .Ar threshold . .It Fl x File system mount points are not traversed. .El .Pp The .Nm utility counts the storage used by symbolic links and not the files they reference unless the .Fl H or .Fl L option is specified. If either the .Fl H or .Fl L option is specified, storage used by any symbolic links which are followed is not counted (or displayed). The .Fl H , .Fl L and .Fl P options override each other and the command's actions are determined by the last one specified. .Pp The -.Fl h, k +.Fl h, k, m and -.Fl m +.Fl Fl si options all override each other; the last one specified determines the block counts used. .Sh ENVIRONMENT .Bl -tag -width BLOCKSIZE .It Ev BLOCKSIZE If the environment variable .Ev BLOCKSIZE is set, and the -.Fl h, k +.Fl h, k, m or -.Fl m +.Fl Fl si options are not specified, the block counts will be displayed in units of that block size. If .Ev BLOCKSIZE is not set, and the -.Fl h, k +.Fl h, k, m or -.Fl m +.Fl Fl si options are not specified, the block counts will be displayed in 512-byte blocks. .El .Sh EXAMPLES Show disk usage for all files in the current directory. Output is in human-readable form: .Pp .Dl # du -ah .Pp Summarize disk usage in the current directory: .Pp .Dl # du -hs .Pp Summarize disk usage for a specific directory: .Pp .Dl # du -hs /home .Pp Show name and size of all C files in a specific directory. Also display a grand total at the end: .Pp .Dl # du -ch /usr/src/sys/kern/*.c .Sh SEE ALSO .Xr df 1 , .Xr chflags 2 , .Xr fts 3 , .Xr symlink 7 , .Xr quot 8 .Sh HISTORY A .Nm command appeared in .At v1 . Index: head/usr.bin/du/du.c =================================================================== --- head/usr.bin/du/du.c (revision 322290) +++ head/usr.bin/du/du.c (revision 322291) @@ -1,543 +1,561 @@ /* * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Newcomb. * * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1989, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static const char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include +#define SI_OPT (CHAR_MAX + 1) + +#define UNITS_2 1 +#define UNITS_SI 2 + static SLIST_HEAD(ignhead, ignentry) ignores; struct ignentry { char *mask; SLIST_ENTRY(ignentry) next; }; static int linkchk(FTSENT *); static void usage(void); static void prthumanval(int64_t); static void ignoreadd(const char *); static void ignoreclean(void); static int ignorep(FTSENT *); static void siginfo(int __unused); static int nodumpflag = 0; -static int Aflag; +static int Aflag, hflag; static long blocksize, cblocksize; static volatile sig_atomic_t info; +static const struct option long_options[] = +{ + { "si", no_argument, NULL, SI_OPT }, + { NULL, no_argument, NULL, 0 }, +}; + int main(int argc, char *argv[]) { FTS *fts; FTSENT *p; off_t savednumber, curblocks; off_t threshold, threshold_sign; int ftsoptions; int depth; int Hflag, Lflag, aflag, sflag, dflag, cflag; - int hflag, lflag, ch, notused, rval; + int lflag, ch, notused, rval; char **save; static char dot[] = "."; setlocale(LC_ALL, ""); - Hflag = Lflag = aflag = sflag = dflag = cflag = hflag = - lflag = Aflag = 0; + Hflag = Lflag = aflag = sflag = dflag = cflag = lflag = Aflag = 0; save = argv; ftsoptions = FTS_PHYSICAL; savednumber = 0; threshold = 0; threshold_sign = 1; cblocksize = DEV_BSIZE; blocksize = 0; depth = INT_MAX; 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) { case 'A': Aflag = 1; break; case 'B': errno = 0; cblocksize = atoi(optarg); if (errno == ERANGE || cblocksize <= 0) { warnx("invalid argument to option B: %s", optarg); usage(); } break; case 'H': Hflag = 1; Lflag = 0; break; case 'I': ignoreadd(optarg); break; case 'L': Lflag = 1; Hflag = 0; break; case 'P': Hflag = Lflag = 0; break; case 'a': aflag = 1; break; case 's': sflag = 1; break; case 'd': dflag = 1; errno = 0; depth = atoi(optarg); if (errno == ERANGE || depth < 0) { warnx("invalid argument to option d: %s", optarg); usage(); } break; case 'c': cflag = 1; break; case 'g': hflag = 0; blocksize = 1073741824; break; case 'h': - hflag = 1; + hflag = UNITS_2; break; case 'k': hflag = 0; blocksize = 1024; break; case 'l': lflag = 1; break; case 'm': hflag = 0; blocksize = 1048576; break; case 'n': nodumpflag = 1; break; case 'r': /* Compatibility. */ break; case 't' : if (expand_number(optarg, &threshold) != 0 || threshold == 0) { warnx("invalid threshold: %s", optarg); usage(); } else if (threshold < 0) threshold_sign = -1; break; case 'x': ftsoptions |= FTS_XDEV; break; + case SI_OPT: + hflag = UNITS_SI; + break; case '?': default: usage(); /* NOTREACHED */ } argc -= optind; argv += optind; /* * XXX * Because of the way that fts(3) works, logical walks will not count * the blocks actually used by symbolic links. We rationalize this by * noting that users computing logical sizes are likely to do logical * copies, so not counting the links is correct. The real reason is * that we'd have to re-implement the kernel's symbolic link traversing * algorithm to get this right. If, for example, you have relative * symbolic links referencing other relative symbolic links, it gets * very nasty, very fast. The bottom line is that it's documented in * the man page, so it's a feature. */ if (Hflag) ftsoptions |= FTS_COMFOLLOW; if (Lflag) { ftsoptions &= ~FTS_PHYSICAL; ftsoptions |= FTS_LOGICAL; } if (!Aflag && (cblocksize % DEV_BSIZE) != 0) cblocksize = howmany(cblocksize, DEV_BSIZE) * DEV_BSIZE; if (aflag + dflag + sflag > 1) usage(); if (sflag) depth = 0; if (!*argv) { argv = save; argv[0] = dot; argv[1] = NULL; } if (blocksize == 0) (void)getbsize(¬used, &blocksize); if (!Aflag) { cblocksize /= DEV_BSIZE; blocksize /= DEV_BSIZE; } if (threshold != 0) threshold = howmany(threshold / DEV_BSIZE * cblocksize, blocksize); rval = 0; (void)signal(SIGINFO, siginfo); if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) err(1, "fts_open"); while ((p = fts_read(fts)) != NULL) { switch (p->fts_info) { case FTS_D: /* Ignore. */ if (ignorep(p)) fts_set(fts, p, FTS_SKIP); break; case FTS_DP: if (ignorep(p)) break; curblocks = Aflag ? howmany(p->fts_statp->st_size, cblocksize) : howmany(p->fts_statp->st_blocks, cblocksize); p->fts_parent->fts_bignum += p->fts_bignum += curblocks; if (p->fts_level <= depth && threshold <= threshold_sign * howmany(p->fts_bignum * cblocksize, blocksize)) { - if (hflag) { + if (hflag > 0) { prthumanval(p->fts_bignum); (void)printf("\t%s\n", p->fts_path); } else { (void)printf("%jd\t%s\n", (intmax_t)howmany(p->fts_bignum * cblocksize, blocksize), p->fts_path); } } if (info) { info = 0; (void)printf("\t%s\n", p->fts_path); } break; case FTS_DC: /* Ignore. */ break; case FTS_DNR: /* Warn, continue. */ case FTS_ERR: case FTS_NS: warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; break; default: if (ignorep(p)) break; if (lflag == 0 && p->fts_statp->st_nlink > 1 && linkchk(p)) break; curblocks = Aflag ? howmany(p->fts_statp->st_size, cblocksize) : howmany(p->fts_statp->st_blocks, cblocksize); if (aflag || p->fts_level == 0) { - if (hflag) { + if (hflag > 0) { prthumanval(curblocks); (void)printf("\t%s\n", p->fts_path); } else { (void)printf("%jd\t%s\n", (intmax_t)howmany(curblocks * cblocksize, blocksize), p->fts_path); } } p->fts_parent->fts_bignum += curblocks; } savednumber = p->fts_parent->fts_bignum; } if (errno) err(1, "fts_read"); if (cflag) { - if (hflag) { + if (hflag > 0) { prthumanval(savednumber); (void)printf("\ttotal\n"); } else { (void)printf("%jd\ttotal\n", (intmax_t)howmany( savednumber * cblocksize, blocksize)); } } ignoreclean(); exit(rval); } static int linkchk(FTSENT *p) { struct links_entry { struct links_entry *next; struct links_entry *previous; int links; dev_t dev; ino_t ino; }; static const size_t links_hash_initial_size = 8192; static struct links_entry **buckets; static struct links_entry *free_list; static size_t number_buckets; static unsigned long number_entries; static char stop_allocating; struct links_entry *le, **new_buckets; struct stat *st; size_t i, new_size; int hash; st = p->fts_statp; /* If necessary, initialize the hash table. */ if (buckets == NULL) { number_buckets = links_hash_initial_size; buckets = malloc(number_buckets * sizeof(buckets[0])); if (buckets == NULL) errx(1, "No memory for hardlink detection"); for (i = 0; i < number_buckets; i++) buckets[i] = NULL; } /* If the hash table is getting too full, enlarge it. */ if (number_entries > number_buckets * 10 && !stop_allocating) { new_size = number_buckets * 2; new_buckets = calloc(new_size, sizeof(struct links_entry *)); /* Try releasing the free list to see if that helps. */ if (new_buckets == NULL && free_list != NULL) { while (free_list != NULL) { le = free_list; free_list = le->next; free(le); } new_buckets = calloc(new_size, sizeof(new_buckets[0])); } if (new_buckets == NULL) { stop_allocating = 1; warnx("No more memory for tracking hard links"); } else { for (i = 0; i < number_buckets; i++) { while (buckets[i] != NULL) { /* Remove entry from old bucket. */ le = buckets[i]; buckets[i] = le->next; /* Add entry to new bucket. */ hash = (le->dev ^ le->ino) % new_size; if (new_buckets[hash] != NULL) new_buckets[hash]->previous = le; le->next = new_buckets[hash]; le->previous = NULL; new_buckets[hash] = le; } } free(buckets); buckets = new_buckets; number_buckets = new_size; } } /* Try to locate this entry in the hash table. */ hash = ( st->st_dev ^ st->st_ino ) % number_buckets; for (le = buckets[hash]; le != NULL; le = le->next) { if (le->dev == st->st_dev && le->ino == st->st_ino) { /* * Save memory by releasing an entry when we've seen * all of its links. */ if (--le->links <= 0) { if (le->previous != NULL) le->previous->next = le->next; if (le->next != NULL) le->next->previous = le->previous; if (buckets[hash] == le) buckets[hash] = le->next; number_entries--; /* Recycle this node through the free list */ if (stop_allocating) { free(le); } else { le->next = free_list; free_list = le; } } return (1); } } if (stop_allocating) return (0); /* Add this entry to the links cache. */ if (free_list != NULL) { /* Pull a node from the free list if we can. */ le = free_list; free_list = le->next; } else /* Malloc one if we have to. */ le = malloc(sizeof(struct links_entry)); if (le == NULL) { stop_allocating = 1; warnx("No more memory for tracking hard links"); return (0); } le->dev = st->st_dev; le->ino = st->st_ino; le->links = st->st_nlink - 1; number_entries++; le->next = buckets[hash]; le->previous = NULL; if (buckets[hash] != NULL) buckets[hash]->previous = le; buckets[hash] = le; return (0); } static void prthumanval(int64_t bytes) { char buf[5]; + int flags; bytes *= cblocksize; + flags = HN_B | HN_NOSPACE | HN_DECIMAL; if (!Aflag) bytes *= DEV_BSIZE; + if (hflag == UNITS_SI) + flags |= HN_DIVISOR_1000; - humanize_number(buf, sizeof(buf), bytes, "", HN_AUTOSCALE, - HN_B | HN_NOSPACE | HN_DECIMAL); + humanize_number(buf, sizeof(buf), bytes, "", HN_AUTOSCALE, flags); (void)printf("%4s", buf); } static void usage(void) { (void)fprintf(stderr, "usage: du [-Aclnx] [-H | -L | -P] [-g | -h | -k | -m] " "[-a | -s | -d depth] [-B blocksize] [-I mask] " "[-t threshold] [file ...]\n"); exit(EX_USAGE); } static void ignoreadd(const char *mask) { struct ignentry *ign; ign = calloc(1, sizeof(*ign)); if (ign == NULL) errx(1, "cannot allocate memory"); ign->mask = strdup(mask); if (ign->mask == NULL) errx(1, "cannot allocate memory"); SLIST_INSERT_HEAD(&ignores, ign, next); } static void ignoreclean(void) { struct ignentry *ign; while (!SLIST_EMPTY(&ignores)) { ign = SLIST_FIRST(&ignores); SLIST_REMOVE_HEAD(&ignores, next); free(ign->mask); free(ign); } } static int ignorep(FTSENT *ent) { struct ignentry *ign; if (nodumpflag && (ent->fts_statp->st_flags & UF_NODUMP)) return 1; SLIST_FOREACH(ign, &ignores, next) if (fnmatch(ign->mask, ent->fts_name, 0) != FNM_NOMATCH) return 1; return 0; } static void siginfo(int sig __unused) { info = 1; } Index: head/usr.bin/du/tests/du_test.sh =================================================================== --- head/usr.bin/du/tests/du_test.sh (revision 322290) +++ head/usr.bin/du/tests/du_test.sh (revision 322291) @@ -1,153 +1,168 @@ # # Copyright (c) 2017 Ngie Cooper # 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. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. # # $FreeBSD$ atf_test_case A_flag A_flag_head() { atf_set "descr" "Verify -A behavior" } A_flag_body() { # XXX: compressed volumes? atf_check truncate -s 10g sparse.file atf_check -o inline:'1\tsparse.file\n' du -g sparse.file atf_check -o inline:'10\tsparse.file\n' du -A -g sparse.file } atf_test_case H_flag H_flag_head() { atf_set "descr" "Verify -H behavior" } H_flag_body() { local paths1='testdir/A/B testdir/A testdir/C testdir' local paths2='testdir/A/B testdir/A testdir/C testdir' local sep='\n[0-9]+\t' atf_check mkdir testdir atf_check -x "cd testdir && mkdir A && touch A/B && ln -s A C" atf_check -o save:du.out du -aAH testdir atf_check egrep -q "[0-9]+\t$(echo $paths1 | tr ' ' "$sep")\n" du.out atf_check -o save:du_C.out du -aAH testdir/C atf_check egrep -q "[0-9]+\t$(echo $paths2 | tr ' ' "$sep")\n" du_C.out } atf_test_case I_flag I_flag_head() { atf_set "descr" "Verify -I behavior" } I_flag_body() { paths_sans_foo_named="a/motley/fool/of/sorts fool/parts/with/their/cache bar baz" paths_foo_named="foo foobar" paths="$paths_sans_foo_named $paths_foo_named" # cd'ing to testdir helps ensure that files from atf/kyua don't # pollute the results. atf_check -x "mkdir testdir && cd testdir && mkdir -p $paths" atf_check -o save:du.out -x "cd testdir && du -s $paths_sans_foo_named" atf_check -o save:du_I.out -x "cd testdir && du -I '*foo*' -s $paths" atf_check diff -u du.out du_I.out } atf_test_case c_flag c_flag_head() { atf_set "descr" "Verify -c output" } c_flag_body() { atf_check truncate -s 0 foo bar } atf_test_case g_flag g_flag_head() { atf_set "descr" "Verify -g output" } g_flag_body() { atf_check truncate -s 1k A atf_check truncate -s 1m B atf_check truncate -s 1g C atf_check truncate -s 1t D atf_check -o inline:'1\tA\n1\tB\n1\tC\n1024\tD\n' du -Ag A B C D } atf_test_case h_flag h_flag_head() { atf_set "descr" "Verify -h output" } h_flag_body() { atf_check truncate -s 1k A atf_check truncate -s 1m B atf_check truncate -s 1g C atf_check truncate -s 1t D atf_check -o inline:'1.0K\tA\n1.0M\tB\n1.0G\tC\n1.0T\tD\n' du -Ah A B C D } atf_test_case k_flag k_flag_head() { atf_set "descr" "Verify -k output" } k_flag_body() { atf_check truncate -s 1k A atf_check truncate -s 1m B atf_check -o inline:'1\tA\n1024\tB\n' du -Ak A B } atf_test_case m_flag m_flag_head() { atf_set "descr" "Verify -m output" } m_flag_body() { atf_check truncate -s 1k A atf_check truncate -s 1m B atf_check truncate -s 1g 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_add_test_case A_flag atf_add_test_case H_flag atf_add_test_case I_flag atf_add_test_case g_flag atf_add_test_case h_flag atf_add_test_case k_flag atf_add_test_case m_flag + atf_add_test_case si_flag }