Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 30 Sep 2019 22:00:48 +0000 (UTC)
From:      Matt Macy <mmacy@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r352923 - head/bin/dd
Message-ID:  <201909302200.x8UM0mU5032395@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mmacy
Date: Mon Sep 30 22:00:48 2019
New Revision: 352923
URL: https://svnweb.freebsd.org/changeset/base/352923

Log:
  Add iflag=fullblock to dd
  
  Normally, count=n means read(2) will be called n times on the input to dd. If
  the read() returns short, as may happen when reading from a pipe, fewer bytes
  will be copied from the input. With conv=sync the buffer is padded with zeros
  to fill the rest of the block.
  
  iflag=fullblock causes dd to continue reading until the block is full, so that
  count=n means n full blocks are copied. This flag is compatible with illumos
  and GNU dd and is used in the ZFS test suite.
  
  Submitted by:	Ryan Moeller
  Reviewed by:	manpages, mmacy@
  MFC after:	1 week
  Sponsored by:	 iXsystems, Inc.
  Differential Revision:	https://reviews.freebsd.org/D21441

Modified:
  head/bin/dd/args.c
  head/bin/dd/dd.1
  head/bin/dd/dd.c
  head/bin/dd/dd.h

Modified: head/bin/dd/args.c
==============================================================================
--- head/bin/dd/args.c	Mon Sep 30 21:56:42 2019	(r352922)
+++ head/bin/dd/args.c	Mon Sep 30 22:00:48 2019	(r352923)
@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
 
 static int	c_arg(const void *, const void *);
 static int	c_conv(const void *, const void *);
+static int	c_iflag(const void *, const void *);
 static int	c_oflag(const void *, const void *);
 static void	f_bs(char *);
 static void	f_cbs(char *);
@@ -66,6 +67,7 @@ static void	f_files(char *);
 static void	f_fillchar(char *);
 static void	f_ibs(char *);
 static void	f_if(char *);
+static void	f_iflag(char *);
 static void	f_obs(char *);
 static void	f_of(char *);
 static void	f_oflag(char *);
@@ -89,6 +91,7 @@ static const struct arg {
 	{ "fillchar",	f_fillchar,	C_FILL,	 C_FILL },
 	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
 	{ "if",		f_if,		C_IF,	 C_IF },
+	{ "iflag",	f_iflag,	0,	 0 },
 	{ "iseek",	f_skip,		C_SKIP,	 C_SKIP },
 	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
 	{ "of",		f_of,		C_OF,	 C_OF },
@@ -259,7 +262,39 @@ f_if(char *arg)
 	in.name = arg;
 }
 
+static const struct iflag {
+	const char *name;
+	uint64_t set, noset;
+} ilist[] = {
+	{ "fullblock",	C_IFULLBLOCK,	C_SYNC },
+};
+
 static void
+f_iflag(char *arg)
+{
+	struct iflag *ip, tmp;
+
+	while (arg != NULL) {
+		tmp.name = strsep(&arg, ",");
+		ip = bsearch(&tmp, ilist, nitems(ilist), sizeof(struct iflag),
+		    c_iflag);
+		if (ip == NULL)
+			errx(1, "unknown iflag %s", tmp.name);
+		if (ddflags & ip->noset)
+			errx(1, "%s: illegal conversion combination", tmp.name);
+		ddflags |= ip->set;
+	}
+}
+
+static int
+c_iflag(const void *a, const void *b)
+{
+
+	return (strcmp(((const struct iflag *)a)->name,
+	    ((const struct iflag *)b)->name));
+}
+
+static void
 f_obs(char *arg)
 {
 	uintmax_t res;
@@ -339,7 +374,7 @@ static const struct conv {
 	{ "parset",	C_PARSET,	C_PARODD|C_PAREVEN|C_PARNONE, NULL},
 	{ "sparse",	C_SPARSE,	0,		NULL },
 	{ "swab",	C_SWAB,		0,		NULL },
-	{ "sync",	C_SYNC,		0,		NULL },
+	{ "sync",	C_SYNC,		C_IFULLBLOCK,	NULL },
 	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
 	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
 };

Modified: head/bin/dd/dd.1
==============================================================================
--- head/bin/dd/dd.1	Mon Sep 30 21:56:42 2019	(r352922)
+++ head/bin/dd/dd.1	Mon Sep 30 22:00:48 2019	(r352923)
@@ -102,6 +102,22 @@ bytes instead of the default 512.
 Read input from
 .Ar file
 instead of the standard input.
+.It Cm iflag Ns = Ns Ar value Ns Op , Ns Ar value ...
+Where
+.Cm value
+is one of the symbols from the following list.
+.Bl -tag -width "fullblock"
+.It Cm fullblock
+Reading from the input file may not obtain a full block.
+When a read returns short, continue reading to fill the block.
+Without this flag,
+.Cm count
+limits the number of times
+.Xr read 2
+is called on the input rather than the number of blocks copied in full.
+May not be combined with
+.Cm conv=sync .
+.El
 .It Cm iseek Ns = Ns Ar n
 Seek on the input file
 .Ar n

Modified: head/bin/dd/dd.c
==============================================================================
--- head/bin/dd/dd.c	Mon Sep 30 21:56:42 2019	(r352922)
+++ head/bin/dd/dd.c	Mon Sep 30 22:00:48 2019	(r352923)
@@ -408,13 +408,15 @@ dd_in(void)
 				memset(in.dbp, 0, in.dbsz);
 		}
 
-		n = read(in.fd, in.dbp, in.dbsz);
-		if (n == 0) {
-			in.dbrcnt = 0;
+		in.dbrcnt = 0;
+fill:
+		n = read(in.fd, in.dbp + in.dbrcnt, in.dbsz - in.dbrcnt);
+
+		/* EOF */
+		if (n == 0 && in.dbrcnt == 0)
 			return;
-		}
 
-		/* Read error. */
+		/* Read error */
 		if (n == -1) {
 			/*
 			 * If noerror not specified, die.  POSIX requires that
@@ -438,26 +440,26 @@ dd_in(void)
 			/* If sync not specified, omit block and continue. */
 			if (!(ddflags & C_SYNC))
 				continue;
+		}
 
-			/* Read errors count as full blocks. */
-			in.dbcnt += in.dbrcnt = in.dbsz;
-			++st.in_full;
+		/* If conv=sync, use the entire block. */
+		if (ddflags & C_SYNC)
+			n = in.dbsz;
 
-		/* Handle full input blocks. */
-		} else if ((size_t)n == (size_t)in.dbsz) {
-			in.dbcnt += in.dbrcnt = n;
-			++st.in_full;
+		/* Count the bytes read for this block. */
+		in.dbrcnt += n;
 
-		/* Handle partial input blocks. */
-		} else {
-			/* If sync, use the entire block. */
-			if (ddflags & C_SYNC)
-				in.dbcnt += in.dbrcnt = in.dbsz;
-			else
-				in.dbcnt += in.dbrcnt = n;
+		/* Count the number of full and partial blocks. */
+		if (in.dbrcnt == in.dbsz)
+			++st.in_full;
+		else if (ddflags & C_IFULLBLOCK && n != 0)
+			goto fill; /* these don't count */
+		else
 			++st.in_part;
-		}
 
+		/* Count the total bytes read for this file. */
+		in.dbcnt += in.dbrcnt;
+
 		/*
 		 * POSIX states that if bs is set and no other conversions
 		 * than noerror, notrunc or sync are specified, the block
@@ -478,6 +480,7 @@ dd_in(void)
 			swapbytes(in.dbp, (size_t)n);
 		}
 
+		/* Advance to the next block. */
 		in.dbp += in.dbrcnt;
 		(*cfunc)();
 		if (need_summary)

Modified: head/bin/dd/dd.h
==============================================================================
--- head/bin/dd/dd.h	Mon Sep 30 21:56:42 2019	(r352922)
+++ head/bin/dd/dd.h	Mon Sep 30 22:00:48 2019	(r352923)
@@ -104,6 +104,7 @@ typedef struct {
 #define	C_FSYNC		0x0000000080000000ULL
 #define	C_FDATASYNC	0x0000000100000000ULL
 #define	C_OFSYNC	0x0000000200000000ULL
+#define	C_IFULLBLOCK	0x0000000400000000ULL
 
 #define	C_PARITY	(C_PAREVEN | C_PARODD | C_PARNONE | C_PARSET)
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201909302200.x8UM0mU5032395>