I have rewritten the patch to add the --total option to df, that was still missing. It compiled and run successfully for me with the latest CVS snapshot (about Sat Aug 19 01:45:57 UTC 2006). I hope it is coded correctly. I tried to follow Eric's advices this time.
Cheers, Gustavo
diff -u -r coreutils.orig/NEWS coreutils/NEWS --- coreutils.orig/NEWS 2006-08-18 21:48:55.000000000 -0300 +++ coreutils/NEWS 2006-08-18 22:30:08.000000000 -0300 @@ -2,6 +2,11 @@ * Major changes in release 6.1-cvs (2006-??-??) [unstable] +** New features + + df now supports a --total (-c) option which prints a grand total + (total capability, usage and availability) of processed filesystems. + ** Bug fixes df (with a command line argument) once again prints its header diff -u -r coreutils.orig/TODO coreutils/TODO --- coreutils.orig/TODO 2006-08-18 21:48:55.000000000 -0300 +++ coreutils/TODO 2006-08-18 22:30:05.000000000 -0300 @@ -37,8 +37,6 @@ printf: consider adapting builtins/printf.def from bash -df: add `--total' option, suggested here http://bugs.debian.org/186007 - seq: give better diagnostics for invalid formats: e.g. no or too many % directives seq: consider allowing format string to contain no %-directives diff -u -r coreutils.orig/doc/coreutils.texi coreutils/doc/coreutils.texi --- coreutils.orig/doc/coreutils.texi 2006-08-18 21:48:55.000000000 -0300 +++ coreutils/doc/coreutils.texi 2006-08-18 22:30:23.000000000 -0300 @@ -9288,6 +9288,15 @@ Scale sizes by @var{size} before printing them (@pxref{Block size}). For example, @option{-BG} prints sizes in units of 1,073,741,824 bytes. [EMAIL PROTECTED] -c [EMAIL PROTECTED] --total [EMAIL PROTECTED] -c [EMAIL PROTECTED] --total [EMAIL PROTECTED] grand total of disk usage +Print a grand total of capability, usage and availability. Every filesystem +that has been processed contributes to the sum. By default totals are not +printed. + @optHumanReadable @item -H diff -u -r coreutils.orig/src/df.c coreutils/src/df.c --- coreutils.orig/src/df.c 2006-08-18 21:48:55.000000000 -0300 +++ coreutils/src/df.c 2006-08-18 22:30:33.000000000 -0300 @@ -112,6 +112,25 @@ /* If true, print file system type as well. */ static bool print_type; +/* If true, print total usage and availability. */ +static bool print_total; + +/* Grand total: amount of blocks and its sign. */ +struct grand_total +{ + uintmax_t n; + bool negate; /* TRUE if N is negative. */ +}; + +/* Total blocks. */ +static struct grand_total total_blocks; + +/* Used blocks. */ +static struct grand_total total_used; + +/* Available (free) blocks. */ +static struct grand_total total_available; + /* For long options that have no equivalent short option, use a non-character as a pseudo short option, starting with CHAR_MAX + 1. */ enum @@ -126,6 +145,7 @@ { {"all", no_argument, NULL, 'a'}, {"block-size", required_argument, NULL, 'B'}, + {"total", no_argument, NULL, 'c'}, {"inodes", no_argument, NULL, 'i'}, {"human-readable", no_argument, NULL, 'h'}, {"si", no_argument, NULL, 'H'}, @@ -231,6 +251,41 @@ return false; } +/* Convert N, which is represented in blocks of FROM_UNIT bytes, + to a representation in blocks of TO_UNIT bytes. It is assumed + that FROM_UNIT and TO_UNIT are valid block sizes. If N is negative + then NEGATE must be TRUE, FLASE otherwise. */ + +static uintmax_t +convert_units (uintmax_t n, bool negate, + uintmax_t from_unit, uintmax_t to_unit) +{ + if (from_unit == to_unit || n == 0) + return n; + else + { + uintmax_t converted; + + if (negate) + n = -n; + + if (from_unit % to_unit == 0) + converted = n * (from_unit / to_unit); + else if (n % to_unit == 0) + converted = (n / to_unit) * from_unit; + else + /* Floating point is necessary. To avoid errors it would + be necessary to use multiple precision arithmetic. */ + { + converted = n * ((long double) from_unit / to_unit); + if (converted != TYPE_MAXIMUM (uintmax_t)) + converted++; + } + + return (negate ? -converted : converted); + } +} + /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS), except: @@ -254,6 +309,52 @@ } } +/* Return how much is used out of total. Total is USED + AVAILABLE. + This code was originally in `show_dev', but since it is needed by + `show_total' this function was created. */ + +static double +percentage_calc (uintmax_t used, bool negate_used, + uintmax_t available, bool negate_available) +{ + double pct = -1; + + if (used == UINTMAX_MAX || available == UINTMAX_MAX) + ; + else if (!negate_used + && used <= TYPE_MAXIMUM (uintmax_t) / 100 + && used + available != 0 + && (used + available < used) == negate_available) + { + uintmax_t u100 = used * 100; + uintmax_t nonroot_total = used + available; + pct = u100 / nonroot_total + (u100 % nonroot_total != 0); + } + else + { + /* The calculation cannot be done easily with integer + arithmetic. Fall back on floating point. This can suffer + from minor rounding errors, but doing it exactly requires + multiple precision arithmetic, and it's not worth the + aggravation. */ + double u = negate_used ? - (double) - used : used; + double a = negate_available ? - (double) - available : available; + double nonroot_total = u + a; + if (nonroot_total) + { + long int lipct = pct = u * 100 / nonroot_total; + double ipct = lipct; + + /* Like `pct = ceil (dpct);', but avoid ceil so that + the math library needn't be linked. */ + if (ipct - 1 < pct && pct <= ipct + 1) + pct = ipct + (ipct < pct); + } + } + + return pct; +} + /* Display a space listing for the disk device with absolute file name DISK. If MOUNT_POINT is non-NULL, it is the name of the root of the file system on DISK. @@ -284,7 +385,7 @@ uintmax_t available_to_root; uintmax_t used; bool negate_used; - double pct = -1; + double pct; if (me_remote & show_local_fs) return; @@ -378,7 +479,7 @@ used = total - available_to_root; negate_used = (total < available_to_root); } - + printf (" %*s %*s %*s ", width, df_readable (false, total, buf[0], input_units, output_units), @@ -387,39 +488,43 @@ width, df_readable (negate_available, available, buf[2], input_units, output_units)); - if (used == UINTMAX_MAX || available == UINTMAX_MAX) - ; - else if (!negate_used - && used <= TYPE_MAXIMUM (uintmax_t) / 100 - && used + available != 0 - && (used + available < used) == negate_available) - { - uintmax_t u100 = used * 100; - uintmax_t nonroot_total = used + available; - pct = u100 / nonroot_total + (u100 % nonroot_total != 0); - } - else - { - /* The calculation cannot be done easily with integer - arithmetic. Fall back on floating point. This can suffer - from minor rounding errors, but doing it exactly requires - multiple precision arithmetic, and it's not worth the - aggravation. */ - double u = negate_used ? - (double) - used : used; - double a = negate_available ? - (double) - available : available; - double nonroot_total = u + a; - if (nonroot_total) - { - long int lipct = pct = u * 100 / nonroot_total; - double ipct = lipct; + if (print_total) + /* Add this filesystem's info to the grand total. We have to be + careful with the signs. */ + { + uintmax_t u = negate_used ? (-used) : used; + uintmax_t a = negate_available ? (-available) : available; + uintmax_t tu = total_used.negate ? (-total_used.n) : total_used.n; + uintmax_t ta = (total_available.negate + ? (-total_available.n) + : total_available.n); + + /* It is not possible just to add the values to the grand total. + Before computing the sum it is needed to convert the values to + a common block size, which happens to be the same as + OUTPUT_BLOCK_SIZE. Following this approach it is possible to + avoid major rounding errors. */ + + uintmax_t default_bsize = inode_format ? 1 : output_block_size; + + total_blocks.negate = false; + total_blocks.n += convert_units (total, false, input_units, + default_bsize); + + total_used.negate = ((negate_used && !(u < tu)) + || (total_used.negate && (u < tu))); + + total_used.n += convert_units(used, negate_used, input_units, + default_bsize); - /* Like `pct = ceil (dpct);', but avoid ceil so that - the math library needn't be linked. */ - if (ipct - 1 < pct && pct <= ipct + 1) - pct = ipct + (ipct < pct); - } - } + total_available.negate = ((negate_available && !(a < ta)) + || (total_available.negate && (a < ta))); + total_available.n += convert_units (available, negate_available, + input_units, default_bsize); + } + + pct = percentage_calc (used, negate_used, available, negate_available); if (0 <= pct) printf ("%*.0f%%", use_width - 1, pct); else @@ -692,6 +797,54 @@ me->me_dummy, me->me_remote); } +/* Show total usage and availability. Every displayed filesystem + contributes with the grand total. */ + +static void +show_total (void) +{ + char buf[3][LONGEST_HUMAN_READABLE + 2]; + int width; + int use_width; + uintmax_t bsize = inode_format ? 1 : output_block_size; + double pct; + + printf("%-20s", _("total")); + + /* Same code used by `show_dev' to determine the correct widths. */ + if (inode_format) + { + width = 7; + use_width = 5; + } + else + { + width = (human_output_opts & human_autoscale + ? 5 + ! (human_output_opts & human_base_1024) + : 9); + use_width = ((posix_format + && ! (human_output_opts & human_autoscale)) + ? 8 : 4); + } + + printf (" %*s %*s %*s ", + width, df_readable (total_blocks.negate, total_blocks.n, + buf[0], bsize, bsize), + width, df_readable (total_used.negate, total_used.n, + buf[1], bsize, bsize), + width, df_readable (total_available.negate, total_available.n, + buf[2], bsize, bsize)); + + pct = percentage_calc (total_used.n, total_used.negate, + total_available.n, total_available.negate); + if (0 <= pct) + printf ("%*.0f%%", use_width - 1, pct); + else + printf ("%*s", use_width, "- "); + + putchar ('\n'); +} + /* Add FSTYPE to the list of file system types to display. */ static void @@ -738,6 +891,7 @@ fputs (_("\ -a, --all include dummy file systems\n\ -B, --block-size=SIZE use SIZE-byte blocks\n\ + -c, --total print total usage and availability\n\ -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\ -H, --si likewise, but use powers of 1000 not 1024\n\ "), stdout); @@ -790,11 +944,12 @@ &output_block_size); print_type = false; + print_total = false; file_systems_processed = false; posix_format = false; exit_status = EXIT_SUCCESS; - while ((c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options, NULL)) + while ((c = getopt_long (argc, argv, "aB:ciF:hHklmPTt:vx:", long_options, NULL)) != -1) { switch (c) @@ -805,6 +960,9 @@ case 'B': human_output_opts = human_options (optarg, true, &output_block_size); break; + case 'c': + print_total = true; + break; case 'i': inode_format = true; break; @@ -943,5 +1101,8 @@ if (! file_systems_processed) error (EXIT_FAILURE, 0, _("no file systems processed")); + if (print_total) + show_total (); + exit (exit_status); }
_______________________________________________ Bug-coreutils mailing list [email protected] http://lists.gnu.org/mailman/listinfo/bug-coreutils
