diff options
-rw-r--r-- | bin/dd/args.c | 9 | ||||
-rw-r--r-- | bin/dd/dd.1 | 8 | ||||
-rw-r--r-- | bin/dd/dd.c | 27 | ||||
-rw-r--r-- | bin/dd/extern.h | 2 | ||||
-rw-r--r-- | bin/dd/misc.c | 21 |
5 files changed, 60 insertions, 7 deletions
diff --git a/bin/dd/args.c b/bin/dd/args.c index 4607d67..27d4a9a 100644 --- a/bin/dd/args.c +++ b/bin/dd/args.c @@ -66,6 +66,7 @@ static void f_obs(char *); static void f_of(char *); static void f_seek(char *); static void f_skip(char *); +static void f_speed(char *); static void f_status(char *); static uintmax_t get_num(const char *); static off_t get_off_t(const char *); @@ -89,6 +90,7 @@ static const struct arg { { "oseek", f_seek, C_SEEK, C_SEEK }, { "seek", f_seek, C_SEEK, C_SEEK }, { "skip", f_skip, C_SKIP, C_SKIP }, + { "speed", f_speed, 0, 0 }, { "status", f_status, C_STATUS,C_STATUS }, }; @@ -295,6 +297,13 @@ f_skip(char *arg) } static void +f_speed(char *arg) +{ + + speed = get_num(arg); +} + +static void f_status(char *arg) { diff --git a/bin/dd/dd.1 b/bin/dd/dd.1 index 4047cdc..64d1acae 100644 --- a/bin/dd/dd.1 +++ b/bin/dd/dd.1 @@ -32,7 +32,7 @@ .\" @(#)dd.1 8.2 (Berkeley) 1/13/94 .\" $FreeBSD$ .\" -.Dd February 4, 2016 +.Dd February 28, 2016 .Dt DD 1 .Os .Sh NAME @@ -156,6 +156,10 @@ Otherwise, input data is read and discarded. For pipes, the correct number of bytes is read. For all other devices, the correct number of blocks is read without distinguishing between a partial or complete block being read. +.It Cm speed Ns = Ns Ar n +Limit the copying speed to +.Ar n +bytes per second. .It Cm status Ns = Ns Ar value Where .Cm value @@ -325,7 +329,7 @@ appended. .El .El .Pp -Where sizes are specified, a decimal, octal, or hexadecimal number of +Where sizes or speed are specified, a decimal, octal, or hexadecimal number of bytes is expected. If the number ends with a .Dq Li b , diff --git a/bin/dd/dd.c b/bin/dd/dd.c index 4c31a5e..56f8efe 100644 --- a/bin/dd/dd.c +++ b/bin/dd/dd.c @@ -82,6 +82,7 @@ size_t cbsz; /* conversion block size */ uintmax_t files_cnt = 1; /* # of files to copy */ const u_char *ctab; /* conversion table */ char fill_char; /* Character to fill with if defined */ +size_t speed = 0; /* maximum speed, in bytes per second */ volatile sig_atomic_t need_summary; int @@ -276,6 +277,29 @@ getfdtype(IO *io) io->flags |= ISSEEK; } +/* + * Limit the speed by adding a delay before every block read. + * The delay (t_usleep) is equal to the time computed from block + * size and the specified speed limit (t_target) minus the time + * spent on actual read and write operations (t_io). + */ +static void +speed_limit(void) +{ + static double t_prev, t_usleep; + double t_now, t_io, t_target; + + t_now = secs_elapsed(); + t_io = t_now - t_prev - t_usleep; + t_target = (double)in.dbsz / (double)speed; + t_usleep = t_target - t_io; + if (t_usleep > 0) + usleep(t_usleep * 1000000); + else + t_usleep = 0; + t_prev = t_now; +} + static void dd_in(void) { @@ -293,6 +317,9 @@ dd_in(void) break; } + if (speed > 0) + speed_limit(); + /* * Zero the buffer first if sync; if doing block operations, * use spaces. diff --git a/bin/dd/extern.h b/bin/dd/extern.h index 6984f6d..25440ca 100644 --- a/bin/dd/extern.h +++ b/bin/dd/extern.h @@ -42,6 +42,7 @@ void def_close(void); void jcl(char **); void pos_in(void); void pos_out(void); +double secs_elapsed(void); void summary(void); void siginfo_handler(int); void terminate(int); @@ -54,6 +55,7 @@ extern void (*cfunc)(void); extern uintmax_t cpy_cnt; extern size_t cbsz; extern u_int ddflags; +extern size_t speed; extern uintmax_t files_cnt; extern const u_char *ctab; extern const u_char a2e_32V[], a2e_POSIX[]; diff --git a/bin/dd/misc.c b/bin/dd/misc.c index eb1227b..ea0f8d3 100644 --- a/bin/dd/misc.c +++ b/bin/dd/misc.c @@ -54,15 +54,12 @@ __FBSDID("$FreeBSD$"); #include "dd.h" #include "extern.h" -void -summary(void) +double +secs_elapsed(void) { struct timespec end, ts_res; double secs, res; - if (ddflags & C_NOINFO) - return; - if (clock_gettime(CLOCK_MONOTONIC, &end)) err(1, "clock_gettime"); if (clock_getres(CLOCK_MONOTONIC, &ts_res)) @@ -72,6 +69,20 @@ summary(void) res = ts_res.tv_sec + ts_res.tv_nsec * 1e-9; if (secs < res) secs = res; + + return (secs); +} + +void +summary(void) +{ + double secs; + + if (ddflags & C_NOINFO) + return; + + secs = secs_elapsed(); + (void)fprintf(stderr, "%ju+%ju records in\n%ju+%ju records out\n", st.in_full, st.in_part, st.out_full, st.out_part); |