From 919156e34c859f4690eff7af344c76cfbe6e8a64 Mon Sep 17 00:00:00 2001 From: Matt Macy Date: Mon, 30 Sep 2019 21:56:42 +0000 Subject: 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. Submitted by: Ryan Moeller Reviewed by: manpages, mmacy@ MFC after: 1 week Sponsored by: iXsytems, Inc. Differential Revision: https://reviews.freebsd.org/D21422 --- bin/dd/args.c | 40 +++++++++++++++++++++++++++++++++++++--- bin/dd/dd.1 | 13 +++++++++++++ bin/dd/dd.c | 20 ++++++++++++++++---- bin/dd/dd.h | 1 + 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/bin/dd/args.c b/bin/dd/args.c index 87385d2d6a91..2624d73094a2 100644 --- a/bin/dd/args.c +++ b/bin/dd/args.c @@ -41,7 +41,7 @@ static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94"; #include __FBSDID("$FreeBSD$"); -#include +#include #include #include @@ -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_oflag(const void *, const void *); static void f_bs(char *); static void f_cbs(char *); static void f_conv(char *); @@ -67,6 +68,7 @@ static void f_ibs(char *); static void f_if(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 *); @@ -90,6 +92,7 @@ static const struct arg { { "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 }, @@ -348,8 +351,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) @@ -368,6 +371,37 @@ c_conv(const void *a, const void *b) ((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 postfix_to_mult(const char expr) { diff --git a/bin/dd/dd.1 b/bin/dd/dd.1 index e1fa48a82520..e68e0dd8bf03 100644 --- a/bin/dd/dd.1 +++ b/bin/dd/dd.1 @@ -123,6 +123,19 @@ If an initial portion of the output file is seeked past (see the .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 diff --git a/bin/dd/dd.c b/bin/dd/dd.c index 64484bd7d564..7977d18b4bfc 100644 --- a/bin/dd/dd.c +++ b/bin/dd/dd.c @@ -143,6 +143,7 @@ static void setup(void) { u_int cnt; + int oflags; cap_rights_t rights; unsigned long cmds[] = { FIODTYPE, MTIOCTOP }; @@ -171,17 +172,28 @@ setup(void) /* 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); } diff --git a/bin/dd/dd.h b/bin/dd/dd.h index a255a5970e52..893e9965e8d3 100644 --- a/bin/dd/dd.h +++ b/bin/dd/dd.h @@ -103,6 +103,7 @@ typedef struct { #define C_PROGRESS 0x0000000040000000ULL #define C_FSYNC 0x0000000080000000ULL #define C_FDATASYNC 0x0000000100000000ULL +#define C_OFSYNC 0x0000000200000000ULL #define C_PARITY (C_PAREVEN | C_PARODD | C_PARNONE | C_PARSET) -- cgit v1.2.3