Module Name: src
Committed By: jym
Date: Sun Nov 6 21:22:23 UTC 2011
Modified Files:
src/bin/dd: Makefile args.c dd.1 dd.c extern.h misc.c
Log Message:
Add a new command to dd(1): msgfmt. The command modifies the
output of the information summary returned by dd(1). This can be used
to specify messages in a more usable (or parseable) format like
human-readable values.
My intent is to re-use this for building image files and quick I/O
benchmarking.
Reviewed by tsutsui@ on tech-userlevel. See also
http://mail-index.netbsd.org/tech-userlevel/2010/12/03/msg004179.html
Some examples:
$ dd if=/dev/zero of=/dev/null bs=1m count=1 msgfmt=human
1+0 records in
1+0 records out
1048576 bytes (1,0 MB) transferred in 0.001 secs (1048576000 bytes/sec - 1,0
GB/sec)
$ dd if=/dev/zero of=/dev/null count=1 msgfmt='
> <speed>%E</speed>
> <time>%s</time>
> <bytes>%b</bytes>
> '
<speed>500 KB/sec</speed>
<time>0.001</time>
<bytes>512</bytes>
To generate a diff of this commit:
cvs rdiff -u -r1.15 -r1.16 src/bin/dd/Makefile
cvs rdiff -u -r1.35 -r1.36 src/bin/dd/args.c
cvs rdiff -u -r1.23 -r1.24 src/bin/dd/dd.1
cvs rdiff -u -r1.47 -r1.48 src/bin/dd/dd.c
cvs rdiff -u -r1.20 -r1.21 src/bin/dd/extern.h
cvs rdiff -u -r1.21 -r1.22 src/bin/dd/misc.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/bin/dd/Makefile
diff -u src/bin/dd/Makefile:1.15 src/bin/dd/Makefile:1.16
--- src/bin/dd/Makefile:1.15 Fri Feb 4 19:42:12 2011
+++ src/bin/dd/Makefile Sun Nov 6 21:22:23 2011
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.15 2011/02/04 19:42:12 pooka Exp $
+# $NetBSD: Makefile,v 1.16 2011/11/06 21:22:23 jym Exp $
# @(#)Makefile 8.1 (Berkeley) 5/31/93
RUMPPRG=dd
@@ -8,7 +8,7 @@ DPADD+= ${LIBUTIL}
LDADD+= -lutil
.ifdef SMALLPROG
-CPPFLAGS+= -DNO_CONV -DSMALL
+CPPFLAGS+= -DNO_CONV -DNO_MSGFMT -DSMALL
.else
SRCS+= conv_tab.c
.ifndef CRUNCHEDPROG
Index: src/bin/dd/args.c
diff -u src/bin/dd/args.c:1.35 src/bin/dd/args.c:1.36
--- src/bin/dd/args.c:1.35 Fri Sep 16 16:06:23 2011
+++ src/bin/dd/args.c Sun Nov 6 21:22:23 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: args.c,v 1.35 2011/09/16 16:06:23 joerg Exp $ */
+/* $NetBSD: args.c,v 1.36 2011/11/06 21:22:23 jym Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94";
#else
-__RCSID("$NetBSD: args.c,v 1.35 2011/09/16 16:06:23 joerg Exp $");
+__RCSID("$NetBSD: args.c,v 1.36 2011/11/06 21:22:23 jym Exp $");
#endif
#endif /* not lint */
@@ -56,15 +56,22 @@ __RCSID("$NetBSD: args.c,v 1.35 2011/09/
#include "extern.h"
static int c_arg(const void *, const void *);
-#ifndef NO_CONV
+
+#ifdef NO_MSGFMT
+static void f_msgfmt(char *) __dead;
+#else
+static void f_msgfmt(char *);
+#endif /* NO_MSGFMT */
+
+#ifdef NO_CONV
+static void f_conv(char *) __dead;
+#else
+static void f_conv(char *);
static int c_conv(const void *, const void *);
-#endif
+#endif /* NO_CONV */
+
static void f_bs(char *);
static void f_cbs(char *);
-#ifdef NO_CONV
-__dead
-#endif
-static void f_conv(char *);
static void f_count(char *);
static void f_files(char *);
static void f_ibs(char *);
@@ -90,6 +97,7 @@ static const struct arg {
{ "ibs", f_ibs, C_IBS, C_BS|C_IBS },
{ "if", f_if, C_IF, C_IF },
{ "iseek", f_skip, C_SKIP, C_SKIP },
+ { "msgfmt", f_msgfmt, C_SKIP, C_SKIP },
{ "obs", f_obs, C_OBS, C_BS|C_OBS },
{ "of", f_of, C_OF, C_OF },
{ "oseek", f_seek, C_SEEK, C_SEEK },
@@ -252,6 +260,24 @@ f_if(char *arg)
in.name = arg;
}
+#ifdef NO_MSGFMT
+/* Build a small version (i.e. for a ramdisk root) */
+static void
+f_msgfmt(char *arg)
+{
+
+ errx(EXIT_FAILURE, "msgfmt option disabled");
+ /* NOTREACHED */
+}
+#else /* NO_MSGFMT */
+static void
+f_msgfmt(char *arg)
+{
+
+ msgfmt = arg;
+}
+#endif /* NO_MSGFMT */
+
static void
f_obs(char *arg)
{
Index: src/bin/dd/dd.1
diff -u src/bin/dd/dd.1:1.23 src/bin/dd/dd.1:1.24
--- src/bin/dd/dd.1:1.23 Wed Dec 22 09:42:53 2010
+++ src/bin/dd/dd.1 Sun Nov 6 21:22:23 2011
@@ -1,4 +1,4 @@
-.\" $NetBSD: dd.1,v 1.23 2010/12/22 09:42:53 enami Exp $
+.\" $NetBSD: dd.1,v 1.24 2011/11/06 21:22:23 jym Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)dd.1 8.2 (Berkeley) 1/13/94
.\"
-.Dd December 22, 2010
+.Dd November 6, 2011
.Dt DD 1
.Os
.Sh NAME
@@ -97,6 +97,74 @@ Seek on the input file
blocks.
This is synonymous with
.Cm skip= Ns Ar n .
+.It Cm msgfmt= Ns Ar fmt
+Specify the message format
+.Ar fmt
+to be used when writing information to standard output.
+Possible values are:
+.Bl -tag -width xxxxx -offset indent -compact
+.It quiet
+turns off information summary report except for errors and
+.Cm progress .
+.It posix
+default information summary report as specified by POSIX.
+.It human
+default information summary report extended with human-readable
+values.
+.El
+.Pp
+When
+.Ar fmt
+does not correspond to any value given above,
+it contains a string that will be used as format specifier
+for the information summary output.
+Each conversion specification is introduced by the character
+.Cm % .
+The following ones are available:
+.Bl -tag -width xx -offset indent -compact
+.It b
+total number of bytes transferred
+.It B
+total number of bytes transferred in
+.Xr humanize_number 3
+format
+.It e
+speed transfer
+.It E
+speed transfer in
+.Xr humanize_number 3
+format
+.It i
+number of partial input block(s)
+.It I
+number of full input block(s)
+.It o
+number of partial output block(s)
+.It O
+number of full output block(s)
+.It s
+time elapsed since the beginning in
+.Do seconds.ms Dc
+format
+.It p
+number of sparse output blocks
+.It t
+number of truncated blocks
+.It w
+number of odd-length swab blocks
+.It P
+singular/plural of
+.Do block Dc
+depending on number of sparse blocks
+.It T
+singular/plural of
+.Do block Dc
+depending on number of truncated blocks
+.It W
+singular/plural of
+.Do block Dc
+depending on number of swab blocks
+.El
.It Cm obs= Ns Ar n
Set the output block size to
.Va n
@@ -370,6 +438,18 @@ will exit.
The
.Nm
utility exits 0 on success and \*[Gt]0 if an error occurred.
+.Sh EXAMPLES
+To print summary information in human-readable form:
+.Pp
+.Dl dd if=/dev/zero of=/dev/null count=1 msgfmt=human
+.Pp
+To customize the information summary output and print it through
+.Xr unvis 3 :
+.Pp
+.Bd -literal -offset indent
+dd if=/dev/zero of=/dev/null count=1 \e
+ msgfmt='speed:%E, in %s seconds\en' 2\*[Gt]\*[Am]1 | unvis
+.Ed
.Sh SEE ALSO
.Xr cp 1 ,
.Xr mt 1 ,
@@ -382,7 +462,9 @@ utility is expected to be a superset of
standard.
The
.Cm files
-operand and the
+and
+.Cm msgfmt
+operands and the
.Cm ascii ,
.Cm ebcdic ,
.Cm ibm ,
Index: src/bin/dd/dd.c
diff -u src/bin/dd/dd.c:1.47 src/bin/dd/dd.c:1.48
--- src/bin/dd/dd.c:1.47 Fri Feb 4 19:42:12 2011
+++ src/bin/dd/dd.c Sun Nov 6 21:22:23 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: dd.c,v 1.47 2011/02/04 19:42:12 pooka Exp $ */
+/* $NetBSD: dd.c,v 1.48 2011/11/06 21:22:23 jym Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -43,7 +43,7 @@ __COPYRIGHT("@(#) Copyright (c) 1991, 19
#if 0
static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94";
#else
-__RCSID("$NetBSD: dd.c,v 1.47 2011/02/04 19:42:12 pooka Exp $");
+__RCSID("$NetBSD: dd.c,v 1.48 2011/11/06 21:22:23 jym Exp $");
#endif
#endif /* not lint */
@@ -86,6 +86,7 @@ u_int files_cnt = 1; /* # of files to
uint64_t progress = 0; /* display sign of life */
const u_char *ctab; /* conversion table */
sigset_t infoset; /* a set blocking SIGINFO */
+const char *msgfmt = "posix"; /* default summary() message format */
/*
* Ops for stdin/stdout and crunch'd dd. These are always host ops.
Index: src/bin/dd/extern.h
diff -u src/bin/dd/extern.h:1.20 src/bin/dd/extern.h:1.21
--- src/bin/dd/extern.h:1.20 Fri Sep 16 16:06:23 2011
+++ src/bin/dd/extern.h Sun Nov 6 21:22:23 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: extern.h,v 1.20 2011/09/16 16:06:23 joerg Exp $ */
+/* $NetBSD: extern.h,v 1.21 2011/11/06 21:22:23 jym Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -74,3 +74,4 @@ extern const u_char a2e_32V[], a2e_POSIX
extern const u_char e2a_32V[], e2a_POSIX[];
extern const u_char a2ibm_32V[], a2ibm_POSIX[];
extern u_char casetab[];
+extern const char *msgfmt;
Index: src/bin/dd/misc.c
diff -u src/bin/dd/misc.c:1.21 src/bin/dd/misc.c:1.22
--- src/bin/dd/misc.c:1.21 Fri Oct 5 07:23:09 2007
+++ src/bin/dd/misc.c Sun Nov 6 21:22:23 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: misc.c,v 1.21 2007/10/05 07:23:09 lukem Exp $ */
+/* $NetBSD: misc.c,v 1.22 2011/11/06 21:22:23 jym Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94";
#else
-__RCSID("$NetBSD: misc.c,v 1.21 2007/10/05 07:23:09 lukem Exp $");
+__RCSID("$NetBSD: misc.c,v 1.22 2011/11/06 21:22:23 jym Exp $");
#endif
#endif /* not lint */
@@ -59,9 +59,42 @@ __RCSID("$NetBSD: misc.c,v 1.21 2007/10/
#define tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
+static void posix_summary(void);
+#ifndef NO_MSGFMT
+static void custom_summary(void);
+static void human_summary(void);
+static void quiet_summary(void);
+
+static void buffer_write(const char *, size_t, int);
+static int dd_write_msg(const char *);
+#endif /* NO_MSGFMT */
+
void
summary(void)
{
+
+ if (progress)
+ (void)write(STDERR_FILENO, "\n", 1);
+
+#ifdef NO_MSGFMT
+ return posix_summary();
+#else /* NO_MSGFMT */
+ if (strncmp(msgfmt, "human", sizeof("human")) == 0)
+ return human_summary();
+
+ if (strncmp(msgfmt, "posix", sizeof("posix")) == 0)
+ return posix_summary();
+
+ if (strncmp(msgfmt, "quiet", sizeof("quiet")) == 0)
+ return quiet_summary();
+
+ return custom_summary();
+#endif /* NO_MSGFMT */
+}
+
+static void
+posix_summary(void)
+{
char buf[100];
int64_t mS;
struct timeval tv;
@@ -73,6 +106,7 @@ summary(void)
mS = tv2mS(tv) - tv2mS(st.start);
if (mS == 0)
mS = 1;
+
/* Use snprintf(3) so that we don't reenter stdio(3). */
(void)snprintf(buf, sizeof(buf),
"%llu+%llu records in\n%llu+%llu records out\n",
@@ -123,3 +157,174 @@ terminate(int signo)
(void)raise_default_signal(signo);
_exit(127);
}
+
+#ifndef NO_MSGFMT
+/*
+ * Buffer write(2) calls
+ */
+static void
+buffer_write(const char *str, size_t size, int flush)
+{
+ static char wbuf[128];
+ static size_t cnt = 0; /* Internal counter to allow wbuf to wrap */
+
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ wbuf[cnt++] = str[i];
+ if (cnt >= sizeof(wbuf) || flush == 1) {
+ (void)write(STDERR_FILENO, wbuf, cnt);
+ cnt = 0;
+ }
+ }
+}
+
+static int
+dd_write_msg(const char *fmt)
+{
+ char hbuf[7], nbuf[32];
+ const char *ptr;
+ int64_t mS;
+ struct timeval tv;
+
+ (void)gettimeofday(&tv, NULL);
+ mS = tv2mS(tv) - tv2mS(st.start);
+ if (mS == 0)
+ mS = 1;
+
+#define ADDC(c) do { buffer_write(&c, 1, 0); } \
+ while (/*CONSTCOND*/0)
+#define ADDS(p) do { buffer_write(p, strlen(p), 0); } \
+ while (/*CONSTCOND*/0)
+
+ for (ptr = fmt; *ptr; ptr++) {
+ if (*ptr != '%') {
+ ADDC(*ptr);
+ continue;
+ }
+
+ switch (*++ptr) {
+ case 'b':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.bytes);
+ ADDS(nbuf);
+ break;
+ case 'B':
+ if (humanize_number(hbuf, sizeof(hbuf),
+ st.bytes, "B",
+ HN_AUTOSCALE, HN_DECIMAL) == -1)
+ warnx("humanize_number (bytes transferred)");
+ ADDS(hbuf);
+ break;
+ case 'e':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long) (st.bytes * 1000LL / mS));
+ ADDS(nbuf);
+ break;
+ case 'E':
+ if (humanize_number(hbuf, sizeof(hbuf),
+ st.bytes * 1000LL / mS, "B",
+ HN_AUTOSCALE, HN_DECIMAL) == -1)
+ warnx("humanize_number (bytes per second)");
+ ADDS(hbuf); ADDS("/sec");
+ break;
+ case 'i':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.in_part);
+ ADDS(nbuf);
+ break;
+ case 'I':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.in_full);
+ ADDS(nbuf);
+ break;
+ case 'o':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.out_part);
+ ADDS(nbuf);
+ break;
+ case 'O':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.out_full);
+ ADDS(nbuf);
+ break;
+ case 's':
+ (void)snprintf(nbuf, sizeof(nbuf), "%li.%03d",
+ (long) (mS / 1000), (int) (mS % 1000));
+ ADDS(nbuf);
+ break;
+ case 'p':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.sparse);
+ ADDS(nbuf);
+ break;
+ case 't':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.trunc);
+ ADDS(nbuf);
+ break;
+ case 'w':
+ (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+ (unsigned long long)st.swab);
+ ADDS(nbuf);
+ break;
+ case 'P':
+ ADDS("block");
+ if (st.sparse != 1) ADDS("s");
+ break;
+ case 'T':
+ ADDS("block");
+ if (st.trunc != 1) ADDS("s");
+ break;
+ case 'W':
+ ADDS("block");
+ if (st.swab != 1) ADDS("s");
+ break;
+ default:
+ ADDS("%");
+ if (*ptr == '\0')
+ goto done;
+ /*FALLTHROUGH*/
+ case '%':
+ ADDC(*ptr);
+ break;
+ }
+ }
+
+done:
+ /* flush buffer */
+ buffer_write("\0", 1, 1);
+ return 0;
+}
+
+static void
+custom_summary(void)
+{
+
+ dd_write_msg(msgfmt);
+}
+
+static void
+human_summary(void)
+{
+ (void)dd_write_msg("%I+%i records in\n%O+%o records out\n");
+ if (st.swab) {
+ (void)dd_write_msg("%w odd length swab %W\n");
+ }
+ if (st.trunc) {
+ (void)dd_write_msg("%t truncated %T\n");
+ }
+ if (st.sparse) {
+ (void)dd_write_msg("%p sparse output %P\n");
+ }
+ (void)dd_write_msg("%b bytes (%B) transferred in %s secs "
+ "(%e bytes/sec - %E)\n");
+}
+
+static void
+quiet_summary(void)
+{
+
+ /* stay quiet */
+}
+#endif /* NO_MSGFMT */