diff options
author | Manuel Novoa III | 2003-03-19 09:13:01 +0000 |
---|---|---|
committer | Manuel Novoa III | 2003-03-19 09:13:01 +0000 |
commit | cad5364599eb5062d59e0c397ed638ddd61a8d5d (patch) | |
tree | a318d0f03aa076c74b576ea45dc543a5669e8e91 /coreutils/du.c | |
parent | e01f9662a5bd5d91be4f6b3941b57fff73cd5af1 (diff) | |
download | busybox-cad5364599eb5062d59e0c397ed638ddd61a8d5d.zip busybox-cad5364599eb5062d59e0c397ed638ddd61a8d5d.tar.gz |
Major coreutils update.
Diffstat (limited to 'coreutils/du.c')
-rw-r--r-- | coreutils/du.c | 227 |
1 files changed, 147 insertions, 80 deletions
diff --git a/coreutils/du.c b/coreutils/du.c index 2e49b21..702a9aa 100644 --- a/coreutils/du.c +++ b/coreutils/du.c @@ -22,45 +22,65 @@ * */ -#include <sys/types.h> -#include <fcntl.h> -#include <dirent.h> -#include <stdio.h> +/* 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. + * 1) Added support for SUSv3 -a, -H, -L, gnu -c, and (busybox) -d options. + * The -d option allows setting of max depth (similar to gnu --max-depth). + * 2) Fixed incorrect size calculations for links and directories, especially + * when errors occurred. Calculates sizes should now match gnu du output. + * 3) Added error checking of output. + * 4) Fixed busybox bug #1284 involving long overflow with human_readable. + */ + #include <stdlib.h> -#include <getopt.h> -#include <string.h> -#include <errno.h> +#include <limits.h> +#include <unistd.h> +#include <dirent.h> +#include <sys/stat.h> #include "busybox.h" - #ifdef CONFIG_FEATURE_HUMAN_READABLE +# ifdef CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K static unsigned long disp_hr = KILOBYTE; +# else +static unsigned long disp_hr = 512; +# endif +#elif defined CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K +static unsigned int disp_k = 1; +#else +static unsigned int disp_k; /* bss inits to 0 */ #endif -static int du_depth /*= 0*/; -static int count_hardlinks /*= 0*/; -static int one_file_system /*= 0*/; +static int max_print_depth = INT_MAX; +static int count_hardlinks = INT_MAX; + +static int status +#if EXIT_SUCCESS == 0 + = EXIT_SUCCESS +#endif + ; +static int print_files; +static int slink_depth; +static int du_depth; +static int one_file_system; static dev_t dir_dev; -static void (*print) (long, char *); -static void print_normal(long size, char *filename) +static void print(long size, char *filename) { + /* TODO - May not want to defer error checking here. */ #ifdef CONFIG_FEATURE_HUMAN_READABLE - printf("%s\t%s\n", make_human_readable_str(size << 10, 1, disp_hr), + bb_printf("%s\t%s\n", make_human_readable_str(size, 512, disp_hr), filename); #else - printf("%ld\t%s\n", size, filename); + bb_printf("%ld\t%s\n", size >> disp_k, filename); #endif } -static void print_summary(long size, char *filename) -{ - if (du_depth == 1) { - print_normal(size, filename); - } -} - /* tiny recursive du */ static long du(char *filename) { @@ -68,23 +88,43 @@ static long du(char *filename) long sum; if ((lstat(filename, &statbuf)) != 0) { - perror_msg("%s", filename); + bb_perror_msg("%s", filename); + status = EXIT_FAILURE; return 0; } - if (du_depth == 0) - dir_dev = statbuf.st_dev; - else if (one_file_system && dir_dev != statbuf.st_dev) - return 0; - du_depth++; - sum = (statbuf.st_blocks >> 1); + if (one_file_system) { + if (du_depth == 0) { + dir_dev = statbuf.st_dev; + } else if (dir_dev != statbuf.st_dev) { + return 0; + } + } + + sum = statbuf.st_blocks; - /* Don't add in stuff pointed to by symbolic links */ if (S_ISLNK(statbuf.st_mode)) { - sum = 0L; - if (du_depth == 1) { + if (slink_depth > du_depth) { /* -H or -L */ + if ((stat(filename, &statbuf)) != 0) { + bb_perror_msg("%s", filename); + status = EXIT_FAILURE; + return 0; + } + sum = statbuf.st_blocks; + if (slink_depth == 1) { + slink_depth = INT_MAX; /* Convert -H to -L. */ + } } } + + if (statbuf.st_nlink > count_hardlinks) { + /* Add files/directories with links only once */ + if (is_in_ino_dev_hashtable(&statbuf, NULL)) { + return 0; + } + add_to_ino_dev_hashtable(&statbuf, NULL); + } + if (S_ISDIR(statbuf.st_mode)) { DIR *dir; struct dirent *entry; @@ -92,8 +132,9 @@ static long du(char *filename) dir = opendir(filename); if (!dir) { - du_depth--; - return 0; + bb_perror_msg("%s", filename); + status = EXIT_FAILURE; + return sum; } newfile = last_char_is(filename, '/'); @@ -103,54 +144,86 @@ static long du(char *filename) while ((entry = readdir(dir))) { char *name = entry->d_name; - if ((strcmp(name, "..") == 0) - || (strcmp(name, ".") == 0)) { + if ((name[0] == '.') && (!name[1] || (name[1] == '.' && !name[2]))) { continue; } newfile = concat_path_file(filename, name); + ++du_depth; sum += du(newfile); + --du_depth; free(newfile); } closedir(dir); + } else if (du_depth > print_files) { + return sum; + } + if (du_depth <= max_print_depth) { print(sum, filename); - } else if (statbuf.st_nlink > 1 && !count_hardlinks) { - /* Add files with hard links only once */ - if (is_in_ino_dev_hashtable(&statbuf, NULL)) { - sum = 0L; - if (du_depth == 1) - print(sum, filename); - } else { - add_to_ino_dev_hashtable(&statbuf, NULL); - } } - du_depth--; return sum; } int du_main(int argc, char **argv) { - int status = EXIT_SUCCESS; - int i; + long total; + int slink_depth_save; + int print_final_total = 0; int c; - /* default behaviour */ - print = print_normal; +#ifdef CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K + if (getenv("POSIXLY_CORRECT")) { /* TODO - a new libbb function? */ +#ifdef CONFIG_FEATURE_HUMAN_READABLE + disp_hr = 512; +#else + disp_k = 0; +#endif + } +#endif + + /* Note: SUSv3 specifies that -a and -s options can not be used together + * in strictly conforming applications. However, it also says that some + * du implementations may produce output when -a and -s are used together. + * gnu du exits with an error code in this case. We choose to simply + * ignore -a. This is consistent with -s being equivalent to -d 0. + */ - /* parse argv[] */ - while ((c = getopt(argc, argv, "slx" + while ((c = getopt(argc, argv, "aHkLsx" "d:" "lc" #ifdef CONFIG_FEATURE_HUMAN_READABLE "hm" #endif - "k")) != EOF) { + )) > 0) { switch (c) { + case 'a': + print_files = INT_MAX; + break; + case 'H': + slink_depth = 1; + break; + case 'k': +#ifdef CONFIG_FEATURE_HUMAN_READABLE + disp_hr = KILOBYTE; +#elif !defined CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K + disp_k = 1; +#endif + break; + case 'L': + slink_depth = INT_MAX; + break; case 's': - print = print_summary; + max_print_depth = 0; + break; + case 'x': + one_file_system = 1; + break; + + case 'd': + max_print_depth = bb_xgetularg10_bnd(optarg, 0, INT_MAX); break; case 'l': count_hardlinks = 1; break; - case 'x': - one_file_system = 1; + case 'c': + print_final_total = 1; break; #ifdef CONFIG_FEATURE_HUMAN_READABLE case 'h': @@ -160,37 +233,31 @@ int du_main(int argc, char **argv) disp_hr = MEGABYTE; break; #endif - case 'k': - break; default: - show_usage(); + bb_show_usage(); } } /* go through remaining args (if any) */ + argv += optind; if (optind >= argc) { - if (du(".") == 0) - status = EXIT_FAILURE; - } else { - long sum; - - for (i = optind; i < argc; i++) { - sum = du(argv[i]); - if (is_directory(argv[i], FALSE, NULL) == FALSE) { - print_normal(sum, argv[i]); - } - reset_ino_dev_hashtable(); + *--argv = "."; + if (slink_depth == 1) { + slink_depth = 0; } } - return status; -} + slink_depth_save = slink_depth; + total = 0; + do { + total += du(*argv); + slink_depth = slink_depth_save; + } while (*++argv); + reset_ino_dev_hashtable(); -/* $Id: du.c,v 1.55 2002/08/23 07:28:45 aaronl Exp $ */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ + if (print_final_total) { + print(total, "total"); + } + + bb_fflush_stdout_and_exit(status); +} |