From 1f271b8f7c9730d72e4ece558da49757dbbf9b7e Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Fri, 26 Sep 2014 17:12:32 +0000 Subject: [PATCH] dd: new status=progress operand * src/dd.c: Report the transfer progress every second when the new status=progress operand is used. * doc/corutils.texi (dd invocation): Document the new progress status operand. * tests/dd/stats.sh: Add new test for status=progress. * NEWS: Mention the feature. --- NEWS | 2 ++ doc/coreutils.texi | 5 +++++ src/dd.c | 63 ++++++++++++++++++++++++++++++++++++------------------ tests/dd/misc.sh | 3 +++ tests/dd/stats.sh | 4 ++++ 5 files changed, 56 insertions(+), 21 deletions(-) diff --git a/NEWS b/NEWS index 3e10ac4..1c16d66 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,8 @@ GNU coreutils NEWS -*- outline -*- king directory. The new option is only permitted if the new root directory is the old "/", and therefore is useful with the --group and --userspec options. + dd status=progress now reports statistics about the data transfer. + ** Changes in behavior chroot changes the current directory to "/" in again - unless the above new diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 6e1a2fb..c93c8cf 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -8649,6 +8649,11 @@ that normally make up the last status line. Do not print any informational or warning messages to stderr. Error messages are output as normal. +@item progress +@opindex progress @r{dd status=} +Print the the transfer rate and volume statistics during the +operation. + @end table @item conv=@var{conversion}[,@var{conversion}]@dots{} diff --git a/src/dd.c b/src/dd.c index a0c5bb1..b84e85e 100644 --- a/src/dd.c +++ b/src/dd.c @@ -136,7 +136,8 @@ enum enum { STATUS_NOXFER = 01, - STATUS_NONE = 02 + STATUS_NONE = 02, + STATUS_PROGRESS = 04 }; /* The name of the input file, or NULL for the standard input. */ @@ -375,6 +376,7 @@ static struct symbol_value const statuses[] = { {"noxfer", STATUS_NOXFER}, {"none", STATUS_NONE}, + {"progress", STATUS_PROGRESS}, {"", 0} }; @@ -732,8 +734,7 @@ multiple_bits_set (int i) /* Print transfer statistics. */ static void -print_stats (void) -{ +print_short_stats (void) { char hbuf[LONGEST_HUMAN_READABLE + 1]; int human_opts = (human_autoscale | human_round_to_nearest @@ -741,24 +742,6 @@ print_stats (void) double delta_s; char const *bytes_per_second; - if (status_flags & STATUS_NONE) - return; - - fprintf (stderr, - _("%"PRIuMAX"+%"PRIuMAX" records in\n" - "%"PRIuMAX"+%"PRIuMAX" records out\n"), - r_full, r_partial, w_full, w_partial); - - if (r_truncate != 0) - fprintf (stderr, - ngettext ("%"PRIuMAX" truncated record\n", - "%"PRIuMAX" truncated records\n", - select_plural (r_truncate)), - r_truncate); - - if (status_flags & STATUS_NOXFER) - return; - /* Use integer arithmetic to compute the transfer rate, since that makes it easy to use SI abbreviations. */ @@ -798,6 +781,30 @@ print_stats (void) fprintf (stderr, _(", %g s, %s/s\n"), delta_s, bytes_per_second); } +static void +print_stats (void) +{ + if (status_flags & STATUS_NONE) + return; + + fprintf (stderr, + _("%"PRIuMAX"+%"PRIuMAX" records in\n" + "%"PRIuMAX"+%"PRIuMAX" records out\n"), + r_full, r_partial, w_full, w_partial); + + if (r_truncate != 0) + fprintf (stderr, + ngettext ("%"PRIuMAX" truncated record\n", + "%"PRIuMAX" truncated records\n", + select_plural (r_truncate)), + r_truncate); + + if (status_flags & STATUS_NOXFER) + return; + + print_short_stats (); +} + /* An ordinary signal was received; arrange for the program to exit. */ static void @@ -1925,6 +1932,8 @@ dd_copy (void) int exit_status = EXIT_SUCCESS; size_t n_bytes_read; + time_t last_progress = 0; + /* Leave at least one extra byte at the beginning and end of 'ibuf' for conv=swab, but keep the buffer address even. But some peculiar device drivers work only with word-aligned buffers, so leave an @@ -2000,6 +2009,18 @@ dd_copy (void) while (1) { + if ((status_flags & STATUS_PROGRESS) && !(status_flags & STATUS_NONE)) + { + int rv; + struct timespec monotime; + rv = clock_gettime(CLOCK_MONOTONIC, &monotime); + if (rv == 0 && monotime.tv_sec - last_progress > 1) + { + last_progress = monotime.tv_sec; + print_short_stats (); + } + } + if (r_partial + r_full >= max_records + !!max_bytes) break; diff --git a/tests/dd/misc.sh b/tests/dd/misc.sh index f877fdd..b141268 100755 --- a/tests/dd/misc.sh +++ b/tests/dd/misc.sh @@ -38,6 +38,9 @@ compare /dev/null err || fail=1 # check status=none is cumulative with status=noxfer dd status=none status=noxfer if=$tmp_in of=/dev/null 2> err || fail=1 compare /dev/null err || fail=1 +# check status=none has precedence over status=progress +dd status=none status=progress if=$tmp_in of=/dev/null 2> err || fail=1 +compare /dev/null err || fail=1 dd if=$tmp_in of=$tmp_out 2> /dev/null || fail=1 compare $tmp_in $tmp_out || fail=1 diff --git a/tests/dd/stats.sh b/tests/dd/stats.sh index 386752e..1fe5b1f 100755 --- a/tests/dd/stats.sh +++ b/tests/dd/stats.sh @@ -54,4 +54,8 @@ for open in '' '1'; do grep '500000000 bytes .* copied' err || { cat err; fail=1; } done +# check status=progress output +timeout 3 dd status=progress if=/dev/zero of=/dev/null 2> err +test $(grep -c 'bytes.*copied' err) -gt 1 || { cat err; fail=1; } + Exit $fail -- 1.9.3