aboutsummaryrefslogtreecommitdiff
path: root/bin/dd
diff options
context:
space:
mode:
authorGlen Barber <gjb@FreeBSD.org>2016-03-02 16:14:46 +0000
committerGlen Barber <gjb@FreeBSD.org>2016-03-02 16:14:46 +0000
commit52259a98adba7622f236db46a330e61df0c84fb1 (patch)
tree9c83d6fb30867514fbcff33f80605a1fb118d720 /bin/dd
parentaef2f6ad2e64655fcc1ab4f9b26e1c7eb20bbe00 (diff)
parent39c44571c032ce86b43e87de4cc716ea696c265d (diff)
downloadsrc-52259a98adba7622f236db46a330e61df0c84fb1.tar.gz
src-52259a98adba7622f236db46a330e61df0c84fb1.zip
MFH
Sponsored by: The FreeBSD Foundation
Notes
Notes: svn path=/projects/release-pkg/; revision=296318
Diffstat (limited to 'bin/dd')
-rw-r--r--bin/dd/args.c9
-rw-r--r--bin/dd/dd.18
-rw-r--r--bin/dd/dd.c27
-rw-r--r--bin/dd/extern.h2
-rw-r--r--bin/dd/misc.c21
5 files changed, 60 insertions, 7 deletions
diff --git a/bin/dd/args.c b/bin/dd/args.c
index 4607d673aa74..27d4a9a36314 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 4047cdca57f5..64d1acae11a9 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 4c31a5e81260..56f8efef7a53 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 6984f6d3b828..25440ca12881 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 eb1227bb5ac6..ea0f8d3d6430 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);