dd: add optional support for status=noxfer/none

While at it, added 'B' number suffixes, upstream compat

function                                             old     new   delta
dd_main                                             1469    1543     +74
dd_suffixes                                           88     112     +24
packed_usage                                       30156   30176     +20
dd_output_status                                     372     388     +16
static.status_words                                    -      13     +13
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 4/0 up/down: 147/0)             Total: 147 bytes

Signed-off-by: Ari Sundholm <ari@tuxera.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Ari Sundholm 2015-02-07 01:41:22 +01:00 committed by Denys Vlasenko
parent 7e66102f76
commit f22a838aed
2 changed files with 111 additions and 70 deletions

View File

@ -87,44 +87,6 @@ config CUT
cut is used to print selected parts of lines from cut is used to print selected parts of lines from
each file to stdout. each file to stdout.
config DD
bool "dd"
default y
help
dd copies a file (from standard input to standard output,
by default) using specific input and output blocksizes,
while optionally performing conversions on it.
config FEATURE_DD_SIGNAL_HANDLING
bool "Enable DD signal handling for status reporting"
default y
depends on DD
help
Sending a SIGUSR1 signal to a running `dd' process makes it
print to standard error the number of records read and written
so far, then to resume copying.
$ dd if=/dev/zero of=/dev/null&
$ pid=$! kill -USR1 $pid; sleep 1; kill $pid
10899206+0 records in
10899206+0 records out
config FEATURE_DD_THIRD_STATUS_LINE
bool "Enable the third status line upon signal"
default y
depends on DD && FEATURE_DD_SIGNAL_HANDLING
help
Displays a coreutils-like third status line with transferred bytes,
elapsed time and speed.
config FEATURE_DD_IBS_OBS
bool "Enable ibs, obs and conv options"
default y
depends on DD
help
Enables support for writing a certain number of bytes in and out,
at a time, and performing conversions on the data stream.
config DF config DF
bool "df" bool "df"
default y default y

View File

@ -8,6 +8,51 @@
* Licensed under GPLv2 or later, see file LICENSE in this source tree. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/ */
//config:config DD
//config: bool "dd"
//config: default y
//config: help
//config: dd copies a file (from standard input to standard output,
//config: by default) using specific input and output blocksizes,
//config: while optionally performing conversions on it.
//config:
//config:config FEATURE_DD_SIGNAL_HANDLING
//config: bool "Enable signal handling for status reporting"
//config: default y
//config: depends on DD
//config: help
//config: Sending a SIGUSR1 signal to a running `dd' process makes it
//config: print to standard error the number of records read and written
//config: so far, then to resume copying.
//config:
//config: $ dd if=/dev/zero of=/dev/null &
//config: $ pid=$!; kill -USR1 $pid; sleep 1; kill $pid
//config: 10899206+0 records in
//config: 10899206+0 records out
//config:
//config:config FEATURE_DD_THIRD_STATUS_LINE
//config: bool "Enable the third status line upon signal"
//config: default y
//config: depends on DD && FEATURE_DD_SIGNAL_HANDLING
//config: help
//config: Displays a coreutils-like third status line with transferred bytes,
//config: elapsed time and speed.
//config:
//config:config FEATURE_DD_IBS_OBS
//config: bool "Enable ibs, obs and conv options"
//config: default y
//config: depends on DD
//config: help
//config: Enables support for writing a certain number of bytes in and out,
//config: at a time, and performing conversions on the data stream.
//config:
//config:config FEATURE_DD_STATUS
//config: bool "Enable status display options"
//config: default y
//config: depends on DD
//config: help
//config: Enables support for status=noxfer/none option.
//usage:#define dd_trivial_usage //usage:#define dd_trivial_usage
//usage: "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" //usage: "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n"
//usage: " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]") //usage: " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]")
@ -32,8 +77,12 @@
//usage: "\n conv=fsync Physically write data out before finishing" //usage: "\n conv=fsync Physically write data out before finishing"
//usage: "\n conv=swab Swap every pair of bytes" //usage: "\n conv=swab Swap every pair of bytes"
//usage: ) //usage: )
//usage: IF_FEATURE_DD_STATUS(
//usage: "\n status=noxfer Suppress rate output"
//usage: "\n status=none Suppress all output"
//usage: )
//usage: "\n" //usage: "\n"
//usage: "\nN may be suffixed by c (1), w (2), b (512), kD (1000), k (1024), MD, M, GD, G" //usage: "\nN may be suffixed by c (1), w (2), b (512), kB (1000), k (1024), MB, M, GB, G"
//usage: //usage:
//usage:#define dd_example_usage //usage:#define dd_example_usage
//usage: "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" //usage: "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n"
@ -54,13 +103,18 @@ static const struct suffix_mult dd_suffixes[] = {
{ "c", 1 }, { "c", 1 },
{ "w", 2 }, { "w", 2 },
{ "b", 512 }, { "b", 512 },
{ "kB", 1000 },
{ "kD", 1000 }, { "kD", 1000 },
{ "k", 1024 }, { "k", 1024 },
{ "K", 1024 }, /* compat with coreutils dd */ { "K", 1024 }, /* compat with coreutils dd (it also accepts KB and KD, TODO?) */
{ "MB", 1000000 },
{ "MD", 1000000 }, { "MD", 1000000 },
{ "M", 1048576 }, { "M", 1024*1024 },
{ "GB", 1000000000 },
{ "GD", 1000000000 }, { "GD", 1000000000 },
{ "G", 1073741824 }, { "G", 1024*1024*1024 },
/* "D" suffix for decimal is not in coreutils manpage, looks like it's deprecated */
/* coreutils also understands TPEZY suffixes for tera- and so on, with B suffix for decimal */
{ "", 0 } { "", 0 }
}; };
@ -70,6 +124,7 @@ struct globals {
unsigned long long total_bytes; unsigned long long total_bytes;
unsigned long long begin_time_us; unsigned long long begin_time_us;
#endif #endif
int flags;
} FIX_ALIASING; } FIX_ALIASING;
#define G (*(struct globals*)&bb_common_bufsiz1) #define G (*(struct globals*)&bb_common_bufsiz1)
#define INIT_G() do { \ #define INIT_G() do { \
@ -77,6 +132,21 @@ struct globals {
memset(&G, 0, sizeof(G)); \ memset(&G, 0, sizeof(G)); \
} while (0) } while (0)
enum {
/* Must be in the same order as OP_conv_XXX! */
/* (see "flags |= (1 << what)" below) */
FLAG_NOTRUNC = (1 << 0) * ENABLE_FEATURE_DD_IBS_OBS,
FLAG_SYNC = (1 << 1) * ENABLE_FEATURE_DD_IBS_OBS,
FLAG_NOERROR = (1 << 2) * ENABLE_FEATURE_DD_IBS_OBS,
FLAG_FSYNC = (1 << 3) * ENABLE_FEATURE_DD_IBS_OBS,
FLAG_SWAB = (1 << 4) * ENABLE_FEATURE_DD_IBS_OBS,
/* end of conv flags */
FLAG_TWOBUFS = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
FLAG_COUNT = 1 << 6,
FLAG_STATUS = 1 << 7,
FLAG_STATUS_NONE = 1 << 7,
FLAG_STATUS_NOXFER = 1 << 8,
};
static void dd_output_status(int UNUSED_PARAM cur_signal) static void dd_output_status(int UNUSED_PARAM cur_signal)
{ {
@ -93,6 +163,13 @@ static void dd_output_status(int UNUSED_PARAM cur_signal)
G.out_full, G.out_part); G.out_full, G.out_part);
#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
# if ENABLE_FEATURE_DD_STATUS
if (G.flags & FLAG_STATUS_NOXFER) /* status=noxfer active? */
return;
//TODO: should status=none make dd stop reacting to USR1 entirely?
//So far we react to it (we print the stats),
//status=none only suppresses final, non-USR1 generated status message.
# endif
fprintf(stderr, "%llu bytes (%sB) copied, ", fprintf(stderr, "%llu bytes (%sB) copied, ",
G.total_bytes, G.total_bytes,
/* show fractional digit, use suffixes */ /* show fractional digit, use suffixes */
@ -148,20 +225,8 @@ static bool write_and_stats(const void *buf, size_t len, size_t obs,
int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int dd_main(int argc UNUSED_PARAM, char **argv) int dd_main(int argc UNUSED_PARAM, char **argv)
{ {
enum {
/* Must be in the same order as OP_conv_XXX! */
/* (see "flags |= (1 << what)" below) */
FLAG_NOTRUNC = (1 << 0) * ENABLE_FEATURE_DD_IBS_OBS,
FLAG_SYNC = (1 << 1) * ENABLE_FEATURE_DD_IBS_OBS,
FLAG_NOERROR = (1 << 2) * ENABLE_FEATURE_DD_IBS_OBS,
FLAG_FSYNC = (1 << 3) * ENABLE_FEATURE_DD_IBS_OBS,
FLAG_SWAB = (1 << 4) * ENABLE_FEATURE_DD_IBS_OBS,
/* end of conv flags */
FLAG_TWOBUFS = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
FLAG_COUNT = 1 << 6,
};
static const char keywords[] ALIGN1 = static const char keywords[] ALIGN1 =
"bs\0""count\0""seek\0""skip\0""if\0""of\0" "bs\0""count\0""seek\0""skip\0""if\0""of\0"IF_FEATURE_DD_STATUS("status\0")
#if ENABLE_FEATURE_DD_IBS_OBS #if ENABLE_FEATURE_DD_IBS_OBS
"ibs\0""obs\0""conv\0" "ibs\0""obs\0""conv\0"
#endif #endif
@ -169,6 +234,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
#if ENABLE_FEATURE_DD_IBS_OBS #if ENABLE_FEATURE_DD_IBS_OBS
static const char conv_words[] ALIGN1 = static const char conv_words[] ALIGN1 =
"notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; "notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
#endif
#if ENABLE_FEATURE_DD_STATUS
static const char status_words[] ALIGN1 =
"none\0""noxfer\0";
#endif #endif
enum { enum {
OP_bs = 0, OP_bs = 0,
@ -177,6 +246,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
OP_skip, OP_skip,
OP_if, OP_if,
OP_of, OP_of,
IF_FEATURE_DD_STATUS(OP_status,)
#if ENABLE_FEATURE_DD_IBS_OBS #if ENABLE_FEATURE_DD_IBS_OBS
OP_ibs, OP_ibs,
OP_obs, OP_obs,
@ -215,14 +285,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
#endif #endif
/* These are all zeroed at once! */ /* These are all zeroed at once! */
struct { struct {
int flags;
size_t oc; size_t oc;
ssize_t prev_read_size; /* for detecting swab failure */ ssize_t prev_read_size; /* for detecting swab failure */
off_t count; off_t count;
off_t seek, skip; off_t seek, skip;
const char *infile, *outfile; const char *infile, *outfile;
} Z; } Z;
#define flags (Z.flags )
#define oc (Z.oc ) #define oc (Z.oc )
#define prev_read_size (Z.prev_read_size) #define prev_read_size (Z.prev_read_size)
#define count (Z.count ) #define count (Z.count )
@ -278,7 +346,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
n = index_in_strings(conv_words, val); n = index_in_strings(conv_words, val);
if (n < 0) if (n < 0)
bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv"); bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv");
flags |= (1 << n); G.flags |= (1 << n);
if (!arg) /* no ',' left, so this was the last specifier */ if (!arg) /* no ',' left, so this was the last specifier */
break; break;
/* *arg = ','; - to preserve ps listing? */ /* *arg = ','; - to preserve ps listing? */
@ -294,7 +362,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
} }
/* These can be large: */ /* These can be large: */
if (what == OP_count) { if (what == OP_count) {
flags |= FLAG_COUNT; G.flags |= FLAG_COUNT;
count = XATOU_SFX(val, dd_suffixes); count = XATOU_SFX(val, dd_suffixes);
/*continue;*/ /*continue;*/
} }
@ -314,6 +382,16 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
outfile = val; outfile = val;
/*continue;*/ /*continue;*/
} }
#if ENABLE_FEATURE_DD_STATUS
if (what == OP_status) {
int n;
n = index_in_strings(status_words, val);
if (n < 0)
bb_error_msg_and_die(bb_msg_invalid_arg, val, "status");
G.flags |= FLAG_STATUS << n;
/*continue;*/
}
#endif
} /* end of "for (argv[i])" */ } /* end of "for (argv[i])" */
//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
@ -321,7 +399,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
obuf = ibuf; obuf = ibuf;
#if ENABLE_FEATURE_DD_IBS_OBS #if ENABLE_FEATURE_DD_IBS_OBS
if (ibs != obs) { if (ibs != obs) {
flags |= FLAG_TWOBUFS; G.flags |= FLAG_TWOBUFS;
obuf = xmalloc(obs); obuf = xmalloc(obs);
} }
#endif #endif
@ -341,12 +419,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
if (outfile) { if (outfile) {
int oflag = O_WRONLY | O_CREAT; int oflag = O_WRONLY | O_CREAT;
if (!seek && !(flags & FLAG_NOTRUNC)) if (!seek && !(G.flags & FLAG_NOTRUNC))
oflag |= O_TRUNC; oflag |= O_TRUNC;
xmove_fd(xopen(outfile, oflag), ofd); xmove_fd(xopen(outfile, oflag), ofd);
if (seek && !(flags & FLAG_NOTRUNC)) { if (seek && !(G.flags & FLAG_NOTRUNC)) {
if (ftruncate(ofd, seek * obs) < 0) { if (ftruncate(ofd, seek * obs) < 0) {
struct stat st; struct stat st;
@ -377,7 +455,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
goto die_outfile; goto die_outfile;
} }
while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
ssize_t n; ssize_t n;
n = safe_read(ifd, ibuf, ibs); n = safe_read(ifd, ibuf, ibs);
@ -385,7 +463,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
break; break;
if (n < 0) { if (n < 0) {
/* "Bad block" */ /* "Bad block" */
if (!(flags & FLAG_NOERROR)) if (!(G.flags & FLAG_NOERROR))
goto die_infile; goto die_infile;
bb_simple_perror_msg(infile); bb_simple_perror_msg(infile);
/* GNU dd with conv=noerror skips over bad blocks */ /* GNU dd with conv=noerror skips over bad blocks */
@ -394,7 +472,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
* conv=noerror just ignores input bad blocks */ * conv=noerror just ignores input bad blocks */
n = 0; n = 0;
} }
if (flags & FLAG_SWAB) { if (G.flags & FLAG_SWAB) {
uint16_t *p16; uint16_t *p16;
ssize_t n2; ssize_t n2;
@ -419,12 +497,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
G.in_full++; G.in_full++;
else { else {
G.in_part++; G.in_part++;
if (flags & FLAG_SYNC) { if (G.flags & FLAG_SYNC) {
memset(ibuf + n, 0, ibs - n); memset(ibuf + n, 0, ibs - n);
n = ibs; n = ibs;
} }
} }
if (flags & FLAG_TWOBUFS) { if (G.flags & FLAG_TWOBUFS) {
char *tmp = ibuf; char *tmp = ibuf;
while (n) { while (n) {
size_t d = obs - oc; size_t d = obs - oc;
@ -446,7 +524,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
goto out_status; goto out_status;
} }
if (flags & FLAG_FSYNC) { if (G.flags & FLAG_FSYNC) {
if (fsync(ofd) < 0) if (fsync(ofd) < 0)
goto die_outfile; goto die_outfile;
} }
@ -468,11 +546,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
exitcode = EXIT_SUCCESS; exitcode = EXIT_SUCCESS;
out_status: out_status:
dd_output_status(0); if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE))
dd_output_status(0);
if (ENABLE_FEATURE_CLEAN_UP) { if (ENABLE_FEATURE_CLEAN_UP) {
free(obuf); free(obuf);
if (flags & FLAG_TWOBUFS) if (G.flags & FLAG_TWOBUFS)
free(ibuf); free(ibuf);
} }