svn commit: r355520 - stable/12/bin/dd
Matt Macy
mmacy at FreeBSD.org
Sun Dec 8 04:19:07 UTC 2019
Author: mmacy
Date: Sun Dec 8 04:19:05 2019
New Revision: 355520
URL: https://svnweb.freebsd.org/changeset/base/355520
Log:
MFC r351770,r352920-r352923
MFCs to dd appear to have been haphazard so selectively
MFCing individually didn't work easily.
Add conv=fsync flag to dd
The fsync flag performs an fsync(2) on the output file before closing it.
This will be useful for the ZFS test suite.
Add conv=fdatasync flag to dd
The fdatasync flag performs an fdatasync(2) on the output file before closing it.
This will be useful for the ZFS test suite.
dd: Check result of close(2) for errors
close(2) can return errors from previous operations which should not be ignored.
Add oflag=fsync and oflag=sync capability to dd
Sets the O_FSYNC flag on the output file. oflag=fsync and oflag=sync are
synonyms just as O_FSYNC and O_SYNC are synonyms. This functionality is
intended to improve portability of dd commands in the ZFS test suite.
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, Thomas Hurst
Reviewed by: manpages, mmacy@
Sponsored by: iXsystems, Inc.
Modified:
stable/12/bin/dd/args.c
stable/12/bin/dd/dd.1
stable/12/bin/dd/dd.c
stable/12/bin/dd/dd.h
stable/12/bin/dd/extern.h
Modified: stable/12/bin/dd/args.c
==============================================================================
--- stable/12/bin/dd/args.c Sun Dec 8 04:17:04 2019 (r355519)
+++ stable/12/bin/dd/args.c Sun Dec 8 04:19:05 2019 (r355520)
@@ -41,7 +41,7 @@ static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
+#include <sys/param.h>
#include <ctype.h>
#include <err.h>
@@ -57,6 +57,8 @@ __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 *);
static void f_conv(char *);
@@ -65,8 +67,10 @@ 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 *);
static void f_seek(char *);
static void f_skip(char *);
static void f_speed(char *);
@@ -77,7 +81,7 @@ static off_t get_off_t(const char *);
static const struct arg {
const char *name;
void (*f)(char *);
- u_int set, noset;
+ uint64_t set, noset;
} args[] = {
{ "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC },
{ "cbs", f_cbs, C_CBS, C_CBS },
@@ -87,9 +91,11 @@ 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 },
+ { "oflag", f_oflag, 0, 0 },
{ "oseek", f_seek, C_SEEK, C_SEEK },
{ "seek", f_seek, C_SEEK, C_SEEK },
{ "skip", f_skip, C_SKIP, C_SKIP },
@@ -256,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;
@@ -314,12 +352,14 @@ f_status(char *arg)
static const struct conv {
const char *name;
- u_int set, noset;
+ uint64_t set, noset;
const u_char *ctab;
} clist[] = {
{ "ascii", C_ASCII, C_EBCDIC, e2a_POSIX },
{ "block", C_BLOCK, C_UNBLOCK, NULL },
{ "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX },
+ { "fdatasync", C_FDATASYNC, 0, NULL },
+ { "fsync", C_FSYNC, 0, NULL },
{ "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX },
{ "lcase", C_LCASE, C_UCASE, NULL },
{ "noerror", C_NOERROR, 0, NULL },
@@ -334,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 },
};
@@ -346,8 +386,8 @@ f_conv(char *arg)
while (arg != NULL) {
tmp.name = strsep(&arg, ",");
- cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv),
- sizeof(struct conv), c_conv);
+ cp = bsearch(&tmp, clist, nitems(clist), sizeof(struct conv),
+ c_conv);
if (cp == NULL)
errx(1, "unknown conversion %s", tmp.name);
if (ddflags & cp->noset)
@@ -364,6 +404,37 @@ c_conv(const void *a, const void *b)
return (strcmp(((const struct conv *)a)->name,
((const struct conv *)b)->name));
+}
+
+static const struct oflag {
+ const char *name;
+ uint64_t set;
+} olist[] = {
+ { "fsync", C_OFSYNC },
+ { "sync", C_OFSYNC },
+};
+
+static void
+f_oflag(char *arg)
+{
+ struct oflag *op, tmp;
+
+ while (arg != NULL) {
+ tmp.name = strsep(&arg, ",");
+ op = bsearch(&tmp, olist, nitems(olist), sizeof(struct oflag),
+ c_oflag);
+ if (op == NULL)
+ errx(1, "unknown open flag %s", tmp.name);
+ ddflags |= op->set;
+ }
+}
+
+static int
+c_oflag(const void *a, const void *b)
+{
+
+ return (strcmp(((const struct oflag *)a)->name,
+ ((const struct oflag *)b)->name));
}
static intmax_t
Modified: stable/12/bin/dd/dd.1
==============================================================================
--- stable/12/bin/dd/dd.1 Sun Dec 8 04:17:04 2019 (r355519)
+++ stable/12/bin/dd/dd.1 Sun Dec 8 04:19:05 2019 (r355520)
@@ -32,7 +32,7 @@
.\" @(#)dd.1 8.2 (Berkeley) 1/13/94
.\" $FreeBSD$
.\"
-.Dd August 8, 2018
+.Dd March 26, 2019
.Dt DD 1
.Os
.Sh NAME
@@ -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
@@ -123,6 +139,19 @@ If an initial portion of the output file is seeked pas
.Cm oseek
operand),
the output file is truncated at that point.
+.It Cm oflag Ns = Ns Ar value Ns Op , Ns Ar value ...
+Where
+.Cm value
+is one of the symbols from the following list.
+.Bl -tag -width "fsync"
+.It Cm fsync
+Set the O_FSYNC flag on the output file to make writes synchronous.
+.It Cm sync
+Set the O_SYNC flag on the output file to make writes synchronous.
+This is synonymous with the
+.Cm fsync
+value.
+.El
.It Cm oseek Ns = Ns Ar n
Seek on the output file
.Ar n
@@ -252,6 +281,14 @@ are maps used in historic
and
.No pre- Ns Bx 4.3 reno
systems.
+.It Cm fdatasync
+Perform an
+.Xr fdatasync 2
+on the output file before closing it.
+.It Cm fsync
+Perform an
+.Xr fsync 2
+on the output file before closing it.
.It Cm lcase
Transform uppercase characters into lowercase characters.
.It Cm pareven , parnone , parodd , parset
@@ -427,7 +464,8 @@ if necessary, to a 1MiB boundary:
.Xr mt 1 ,
.Xr recoverdisk 1 ,
.Xr tr 1 ,
-.Xr geom 4
+.Xr geom 4 ,
+.Xr trim 8
.Sh STANDARDS
The
.Nm
Modified: stable/12/bin/dd/dd.c
==============================================================================
--- stable/12/bin/dd/dd.c Sun Dec 8 04:17:04 2019 (r355519)
+++ stable/12/bin/dd/dd.c Sun Dec 8 04:19:05 2019 (r355520)
@@ -83,7 +83,7 @@ STAT st; /* statistics */
void (*cfunc)(void); /* conversion function */
uintmax_t cpy_cnt; /* # of blocks to copy */
static off_t pending = 0; /* pending seek if sparse */
-u_int ddflags = 0; /* conversion options */
+uint64_t ddflags = 0; /* conversion options */
size_t cbsz; /* conversion block size */
uintmax_t files_cnt = 1; /* # of files to copy */
const u_char *ctab; /* conversion table */
@@ -124,7 +124,8 @@ main(int argc __unused, char *argv[])
* descriptor explicitly so that the summary handler (called
* from an atexit() hook) includes this work.
*/
- close(out.fd);
+ if (close(out.fd) == -1 && errno != EINTR)
+ err(1, "close");
exit(0);
}
@@ -142,6 +143,7 @@ static void
setup(void)
{
u_int cnt;
+ int oflags;
cap_rights_t rights;
unsigned long cmds[] = { FIODTYPE, MTIOCTOP };
@@ -164,21 +166,34 @@ setup(void)
errx(1, "files is not supported for non-tape devices");
cap_rights_set(&rights, CAP_FTRUNCATE, CAP_IOCTL, CAP_WRITE);
+ if (ddflags & (C_FDATASYNC | C_FSYNC))
+ cap_rights_set(&rights, CAP_FSYNC);
if (out.name == NULL) {
/* No way to check for read access here. */
out.fd = STDOUT_FILENO;
out.name = "stdout";
+ if (ddflags & C_OFSYNC) {
+ oflags = fcntl(out.fd, F_GETFL);
+ if (oflags == -1)
+ err(1, "unable to get fd flags for stdout");
+ oflags |= O_FSYNC;
+ if (fcntl(out.fd, F_SETFL, oflags) == -1)
+ err(1, "unable to set fd flags for stdout");
+ }
} else {
-#define OFLAGS \
- (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
- out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
+ oflags = O_CREAT;
+ if (!(ddflags & (C_SEEK | C_NOTRUNC)))
+ oflags |= O_TRUNC;
+ if (ddflags & C_OFSYNC)
+ oflags |= O_FSYNC;
+ out.fd = open(out.name, O_RDWR | oflags, DEFFILEMODE);
/*
* May not have read access, so try again with write only.
* Without read we may have a problem if output also does
* not support seeks.
*/
if (out.fd == -1) {
- out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
+ out.fd = open(out.name, O_WRONLY | oflags, DEFFILEMODE);
out.flags |= NOREAD;
cap_rights_clear(&rights, CAP_READ);
}
@@ -393,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
@@ -423,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
@@ -463,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)
@@ -504,6 +522,14 @@ dd_close(void)
if (out.seek_offset > 0 && (out.flags & ISTRUNC)) {
if (ftruncate(out.fd, out.seek_offset) == -1)
err(1, "truncating %s", out.name);
+ }
+
+ if (ddflags & C_FSYNC) {
+ if (fsync(out.fd) == -1)
+ err(1, "fsyncing %s", out.name);
+ } else if (ddflags & C_FDATASYNC) {
+ if (fdatasync(out.fd) == -1)
+ err(1, "fdatasyncing %s", out.name);
}
}
Modified: stable/12/bin/dd/dd.h
==============================================================================
--- stable/12/bin/dd/dd.h Sun Dec 8 04:17:04 2019 (r355519)
+++ stable/12/bin/dd/dd.h Sun Dec 8 04:19:05 2019 (r355520)
@@ -70,37 +70,41 @@ typedef struct {
} STAT;
/* Flags (in ddflags). */
-#define C_ASCII 0x00000001
-#define C_BLOCK 0x00000002
-#define C_BS 0x00000004
-#define C_CBS 0x00000008
-#define C_COUNT 0x00000010
-#define C_EBCDIC 0x00000020
-#define C_FILES 0x00000040
-#define C_IBS 0x00000080
-#define C_IF 0x00000100
-#define C_LCASE 0x00000200
-#define C_NOERROR 0x00000400
-#define C_NOTRUNC 0x00000800
-#define C_OBS 0x00001000
-#define C_OF 0x00002000
-#define C_OSYNC 0x00004000
-#define C_PAREVEN 0x00008000
-#define C_PARNONE 0x00010000
-#define C_PARODD 0x00020000
-#define C_PARSET 0x00040000
-#define C_SEEK 0x00080000
-#define C_SKIP 0x00100000
-#define C_SPARSE 0x00200000
-#define C_SWAB 0x00400000
-#define C_SYNC 0x00800000
-#define C_UCASE 0x01000000
-#define C_UNBLOCK 0x02000000
-#define C_FILL 0x04000000
-#define C_STATUS 0x08000000
-#define C_NOXFER 0x10000000
-#define C_NOINFO 0x20000000
-#define C_PROGRESS 0x40000000
+#define C_ASCII 0x0000000000000001ULL
+#define C_BLOCK 0x0000000000000002ULL
+#define C_BS 0x0000000000000004ULL
+#define C_CBS 0x0000000000000008ULL
+#define C_COUNT 0x0000000000000010ULL
+#define C_EBCDIC 0x0000000000000020ULL
+#define C_FILES 0x0000000000000040ULL
+#define C_IBS 0x0000000000000080ULL
+#define C_IF 0x0000000000000100ULL
+#define C_LCASE 0x0000000000000200ULL
+#define C_NOERROR 0x0000000000000400ULL
+#define C_NOTRUNC 0x0000000000000800ULL
+#define C_OBS 0x0000000000001000ULL
+#define C_OF 0x0000000000002000ULL
+#define C_OSYNC 0x0000000000004000ULL
+#define C_PAREVEN 0x0000000000008000ULL
+#define C_PARNONE 0x0000000000010000ULL
+#define C_PARODD 0x0000000000020000ULL
+#define C_PARSET 0x0000000000040000ULL
+#define C_SEEK 0x0000000000080000ULL
+#define C_SKIP 0x0000000000100000ULL
+#define C_SPARSE 0x0000000000200000ULL
+#define C_SWAB 0x0000000000400000ULL
+#define C_SYNC 0x0000000000800000ULL
+#define C_UCASE 0x0000000001000000ULL
+#define C_UNBLOCK 0x0000000002000000ULL
+#define C_FILL 0x0000000004000000ULL
+#define C_STATUS 0x0000000008000000ULL
+#define C_NOXFER 0x0000000010000000ULL
+#define C_NOINFO 0x0000000020000000ULL
+#define C_PROGRESS 0x0000000040000000ULL
+#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)
Modified: stable/12/bin/dd/extern.h
==============================================================================
--- stable/12/bin/dd/extern.h Sun Dec 8 04:17:04 2019 (r355519)
+++ stable/12/bin/dd/extern.h Sun Dec 8 04:19:05 2019 (r355520)
@@ -58,7 +58,7 @@ extern STAT st;
extern void (*cfunc)(void);
extern uintmax_t cpy_cnt;
extern size_t cbsz;
-extern u_int ddflags;
+extern uint64_t ddflags;
extern size_t speed;
extern uintmax_t files_cnt;
extern const u_char *ctab;
More information about the svn-src-stable
mailing list