tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: humanize_number(3) for dd(1) summary?



On 04.11.2011 12:11, Izumi Tsutsui wrote:
On 03.11.2011 18:53, Jean-Yves Migeon wrote:
Can't dd_snprintf() be also optional if it occupies ~2.5KiB?

I can; there's one trade off though:

- the SMALLPROG dd(1) becomes smaller (by about 2.2kiB), which is still
approx. 200 bytes bigger than the original SMALLPROG dd(1)

- the normal dd(1) becomes bigger (approx. 600B), as we don't factor
posix/human/quiet summary() anymore.

Forgot to ask -- which way you prefer? I don't mind, personally.

I'd like smaller SMALLPROG one, for people who want dd(1)
on rescue media to zap leftover labels on their disks etc.

okay, last call, this time with an updated dd(1).

If nobody objects I'll commit it in a few days.

--
Jean-Yves Migeon
jeanyves.migeon%free.fr@localhost
Index: Makefile
===================================================================
RCS file: /cvsroot/src/bin/dd/Makefile,v
retrieving revision 1.15
diff -u -p -r1.15 Makefile
--- Makefile    4 Feb 2011 19:42:12 -0000       1.15
+++ Makefile    5 Nov 2011 01:42:13 -0000
@@ -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: args.c
===================================================================
RCS file: /cvsroot/src/bin/dd/args.c,v
retrieving revision 1.35
diff -u -p -r1.35 args.c
--- args.c      16 Sep 2011 16:06:23 -0000      1.35
+++ args.c      5 Nov 2011 01:42:13 -0000
@@ -64,11 +64,13 @@ 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 *);
 static void    f_if(char *);
+static void    f_msgfmt(char *);
 static void    f_obs(char *);
 static void    f_of(char *);
 static void    f_seek(char *);
@@ -90,6 +92,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 +255,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: dd.1
===================================================================
RCS file: /cvsroot/src/bin/dd/dd.1,v
retrieving revision 1.23
diff -u -p -r1.23 dd.1
--- dd.1        22 Dec 2010 09:42:53 -0000      1.23
+++ dd.1        5 Nov 2011 01:42:14 -0000
@@ -32,7 +32,7 @@
 .\"
 .\"    @(#)dd.1        8.2 (Berkeley) 1/13/94
 .\"
-.Dd December 22, 2010
+.Dd November 05, 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: dd.c
===================================================================
RCS file: /cvsroot/src/bin/dd/dd.c,v
retrieving revision 1.47
diff -u -p -r1.47 dd.c
--- dd.c        4 Feb 2011 19:42:12 -0000       1.47
+++ dd.c        5 Nov 2011 01:42:14 -0000
@@ -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: extern.h
===================================================================
RCS file: /cvsroot/src/bin/dd/extern.h,v
retrieving revision 1.20
diff -u -p -r1.20 extern.h
--- extern.h    16 Sep 2011 16:06:23 -0000      1.20
+++ extern.h    5 Nov 2011 01:42:14 -0000
@@ -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: misc.c
===================================================================
RCS file: /cvsroot/src/bin/dd/misc.c,v
retrieving revision 1.21
diff -u -p -r1.21 misc.c
--- misc.c      5 Oct 2007 07:23:09 -0000       1.21
+++ misc.c      5 Nov 2011 01:42:14 -0000
@@ -59,9 +59,41 @@ __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 int  dd_snprintf(char *, size_t, 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;
@@ -123,3 +155,169 @@ terminate(int signo)
        (void)raise_default_signal(signo);
        _exit(127);
 }
+
+#ifndef NO_MSGFMT
+static int
+dd_snprintf(char *sbuf, size_t len, const char *fmt)
+{
+       char nbuf[64], hbuf[7];
+       char *ebuf = &sbuf[len - 1], *buf = sbuf;
+       const char *ptr, *s;
+       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 { if (buf < ebuf) *buf++ = c; else buf++; } \
+       while (/*CONSTCOND*/0)
+#define ADDS(p) do { for (s = p; *s; s++) ADDC(*s); } \
+       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:
+                       ADDC('%');
+                       if (*ptr == '\0')
+                               goto done;
+                       /*FALLTHROUGH*/
+               case '%':
+                       ADDC(*ptr);
+                       break;
+               }
+       }
+
+done:
+       if (buf < ebuf)
+               *buf = '\0';
+       else if (len != 0)
+               sbuf[len - 1] = '\0';
+       return (int)(buf - sbuf);
+}
+
+static void
+custom_summary(void)
+{
+       char buf[1024];
+
+       (void)dd_snprintf(buf, sizeof(buf), msgfmt);
+
+       (void)write(STDERR_FILENO, buf, strlen(buf));
+}
+
+static void
+human_summary(void)
+{
+       char buf[100];
+
+       /* Use snprintf(3) so that we don't reenter stdio(3). */
+       (void)dd_snprintf(buf, sizeof(buf),
+           "%I+%i records in\n%O+%o records out\n");
+       (void)write(STDERR_FILENO, buf, strlen(buf));
+       if (st.swab) {
+               (void)dd_snprintf(buf, sizeof(buf), "%w odd length swab %W\n");
+               (void)write(STDERR_FILENO, buf, strlen(buf));
+       }
+       if (st.trunc) {
+               (void)dd_snprintf(buf, sizeof(buf), "%t truncated %T\n");
+               (void)write(STDERR_FILENO, buf, strlen(buf));
+       }
+       if (st.sparse) {
+               (void)dd_snprintf(buf, sizeof(buf), "%p sparse output %P\n");
+               (void)write(STDERR_FILENO, buf, strlen(buf));
+       }
+       (void)dd_snprintf(buf, sizeof(buf),
+           "%b bytes (%B) transferred in %s secs (%e bytes/sec - %E)\n");
+       (void)write(STDERR_FILENO, buf, strlen(buf));
+}
+
+static void
+quiet_summary(void)
+{
+
+       /* stay quiet */
+}
+#endif /* NO_MSGFMT */


Home | Main Index | Thread Index | Old Index