hush: rename hush-redir/redir3.tests (ash has redir3.tests which id different)
[oweals/busybox.git] / coreutils / du.c
index 730d6d162eb4fccceedce4bdb08dcc79a7e83978..03e31a0e4109d7c7a70c652a850a1c2981e9a366 100644 (file)
@@ -6,12 +6,8 @@
  * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
  * Copyright (C) 2002  Edward Betts <edward@debian.org>
  *
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
-
-/* BB_AUDIT SUSv3 compliant (unless default blocksize set to 1k) */
-/* http://www.opengroup.org/onlinepubs/007904975/utilities/du.html */
-
 /* Mar 16, 2003      Manuel Novoa III   (mjn3@codepoet.org)
  *
  * Mostly rewritten for SUSv3 compliance and to fix bugs/defects.
  * 3) Added error checking of output.
  * 4) Fixed busybox bug #1284 involving long overflow with human_readable.
  */
+//config:config DU
+//config:      bool "du (default blocksize of 512 bytes)"
+//config:      default y
+//config:      help
+//config:        du is used to report the amount of disk space used
+//config:        for specified files.
+//config:
+//config:config FEATURE_DU_DEFAULT_BLOCKSIZE_1K
+//config:      bool "Use a default blocksize of 1024 bytes (1K)"
+//config:      default y
+//config:      depends on DU
+//config:      help
+//config:        Use a blocksize of (1K) instead of the default 512b.
+
+//applet:IF_DU(APPLET(du, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_DU) += du.o
+
+/* BB_AUDIT SUSv3 compliant (unless default blocksize set to 1k) */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/du.html */
+
+//usage:#define du_trivial_usage
+//usage:       "[-aHLdclsx" IF_FEATURE_HUMAN_READABLE("hm") "k] [FILE]..."
+//usage:#define du_full_usage "\n\n"
+//usage:       "Summarize disk space used for each FILE and/or directory\n"
+//usage:     "\n       -a      Show file sizes too"
+//usage:     "\n       -L      Follow all symlinks"
+//usage:     "\n       -H      Follow symlinks on command line"
+//usage:     "\n       -d N    Limit output to directories (and files with -a) of depth < N"
+//usage:     "\n       -c      Show grand total"
+//usage:     "\n       -l      Count sizes many times if hard linked"
+//usage:     "\n       -s      Display only a total for each argument"
+//usage:     "\n       -x      Skip directories on different filesystems"
+//usage:       IF_FEATURE_HUMAN_READABLE(
+//usage:     "\n       -h      Sizes in human readable format (e.g., 1K 243M 2G)"
+//usage:     "\n       -m      Sizes in megabytes"
+//usage:       )
+//usage:     "\n       -k      Sizes in kilobytes" IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(" (default)")
+//usage:       IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(
+//usage:     "\n               Default unit is 512 bytes"
+//usage:       )
+//usage:
+//usage:#define du_example_usage
+//usage:       "$ du\n"
+//usage:       "16      ./CVS\n"
+//usage:       "12      ./kernel-patches/CVS\n"
+//usage:       "80      ./kernel-patches\n"
+//usage:       "12      ./tests/CVS\n"
+//usage:       "36      ./tests\n"
+//usage:       "12      ./scripts/CVS\n"
+//usage:       "16      ./scripts\n"
+//usage:       "12      ./docs/CVS\n"
+//usage:       "104     ./docs\n"
+//usage:       "2417    .\n"
 
 #include "libbb.h"
+#include "common_bufsiz.h"
 
 enum {
        OPT_a_files_too    = (1 << 0),
@@ -41,7 +92,7 @@ enum {
 
 struct globals {
 #if ENABLE_FEATURE_HUMAN_READABLE
-       unsigned long disp_hr;
+       unsigned long disp_unit;
 #else
        unsigned disp_k;
 #endif
@@ -50,33 +101,47 @@ struct globals {
        int slink_depth;
        int du_depth;
        dev_t dir_dev;
-};
-#define G (*(struct globals*)&bb_common_bufsiz1)
+} FIX_ALIASING;
+#define G (*(struct globals*)bb_common_bufsiz1)
+#define INIT_G() do { setup_common_bufsiz(); } while (0)
 
 
-static void print(unsigned long size, const char *filename)
+static void print(unsigned long long size, const char *filename)
 {
        /* TODO - May not want to defer error checking here. */
 #if ENABLE_FEATURE_HUMAN_READABLE
+# if ENABLE_DESKTOP
+       /* ~30 bytes of code for extra comtat:
+        * coreutils' du rounds sizes up:
+        * for example,  1025k file is shown as "2" by du -m.
+        * We round to nearest if human-readable [too hard to fix],
+        * else (fixed scale such as -m), we round up. To that end,
+        * add yet another half of the unit before displaying:
+        */
+       if (G.disp_unit)
+               size += (G.disp_unit-1) / (unsigned)(512 * 2);
+# endif
        printf("%s\t%s\n",
-                       /* size x 512 / G.disp_hr, show one fractional,
-                        * use suffixes if G.disp_hr == 0 */
-                       make_human_readable_str(size, 512, G.disp_hr),
+                       /* size x 512 / G.disp_unit.
+                        * If G.disp_unit == 0, show one fractional
+                        * and use suffixes
+                        */
+                       make_human_readable_str(size, 512, G.disp_unit),
                        filename);
 #else
        if (G.disp_k) {
                size++;
                size >>= 1;
        }
-       printf("%lu\t%s\n", size, filename);
+       printf("%llu\t%s\n", size, filename);
 #endif
 }
 
 /* tiny recursive du */
-static unsigned long du(const char *filename)
+static unsigned long long du(const char *filename)
 {
        struct stat statbuf;
-       unsigned long sum;
+       unsigned long long sum;
 
        if (lstat(filename, &statbuf) != 0) {
                bb_simple_perror_msg(filename);
@@ -153,15 +218,17 @@ static unsigned long du(const char *filename)
 int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int du_main(int argc UNUSED_PARAM, char **argv)
 {
-       unsigned long total;
+       unsigned long long total;
        int slink_depth_save;
        unsigned opt;
 
+       INIT_G();
+
 #if ENABLE_FEATURE_HUMAN_READABLE
-       IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 1024;)
-       IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 512;)
+       IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_unit = 1024;)
+       IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_unit = 512;)
        if (getenv("POSIXLY_CORRECT"))  /* TODO - a new libbb function? */
-               G.disp_hr = 512;
+               G.disp_unit = 512;
 #else
        IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 1;)
        /* IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 0;) - G is pre-zeroed */
@@ -175,21 +242,21 @@ int du_main(int argc UNUSED_PARAM, char **argv)
         * ignore -a.  This is consistent with -s being equivalent to -d 0.
         */
 #if ENABLE_FEATURE_HUMAN_READABLE
-       opt_complementary = "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s:d+";
-       opt = getopt32(argv, "aHkLsx" "d:" "lc" "hm", &G.max_print_depth);
+       opt_complementary = "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s";
+       opt = getopt32(argv, "aHkLsx" "d:+" "lc" "hm", &G.max_print_depth);
        argv += optind;
        if (opt & OPT_h_for_humans) {
-               G.disp_hr = 0;
+               G.disp_unit = 0;
        }
        if (opt & OPT_m_mbytes) {
-               G.disp_hr = 1024*1024;
+               G.disp_unit = 1024*1024;
        }
        if (opt & OPT_k_kbytes) {
-               G.disp_hr = 1024;
+               G.disp_unit = 1024;
        }
 #else
-       opt_complementary = "H-L:L-H:s-d:d-s:d+";
-       opt = getopt32(argv, "aHkLsx" "d:" "lc", &G.max_print_depth);
+       opt_complementary = "H-L:L-H:s-d:d-s";
+       opt = getopt32(argv, "aHkLsx" "d:+" "lc", &G.max_print_depth);
        argv += optind;
 #if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
        if (opt & OPT_k_kbytes) {