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 */

Reply via email to