aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2020-10-13 20:27:48 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2020-10-13 20:27:48 +0000
commit4ca8449c2826be469bc9558f2a037236c6703d64 (patch)
treef4822e70e3a382a651636a46271bd4e4407f7f6a
parent050aa4385fef1eb0ef515bdc97c47dc24858354a (diff)
downloadsg3_utils-4ca8449c2826be469bc9558f2a037236c6703d64.tar.gz
sg_dd: add oflag=nocreat and conv=nocreat : OFILE must exist; similar in testing sgh_dd+sg_mrq_dd
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@865 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog3
-rw-r--r--debian/changelog2
-rw-r--r--doc/sg_dd.814
-rw-r--r--sg3_utils.spec2
-rw-r--r--src/sg_dd.c47
-rw-r--r--testing/sg_mrq_dd.cpp82
-rw-r--r--testing/sgh_dd.cpp72
7 files changed, 171 insertions, 51 deletions
diff --git a/ChangeLog b/ChangeLog
index 6d817281..2a4337c1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,13 +2,14 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.46 [20201009] [svn: r864]
+Changelog for sg3_utils-1.46 [20201013] [svn: r865]
- sg_rep_pip: report new provisioning initialization pattern cmd
- sg_turs: estimated time-to-ready [20-061r2]
- add --delay=MS option
- sg_requests: substantial cleanup
- sg_dd: --verify : separate category for miscompare errors
- --verify : oflag=coe continue on miscompares, counts them
+ - add oflag=nocreat and conv=nocreat : OFILE must exist
- add iflag=00,ff, random flags
- sg_get_elem_status: add ralwd bit sbc4r20a
- sg_write_x: add dld bits to write(32) [sbc4r19a]
diff --git a/debian/changelog b/debian/changelog
index 3240f61b..99589f79 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@ sg3-utils (1.46-0.1) unstable; urgency=low
* New upstream version
- -- Douglas Gilbert <dgilbert@interlog.com> Tue, 01 Sep 2020 11:00:00 -0400
+ -- Douglas Gilbert <dgilbert@interlog.com> Tue, 13 Oct 2020 01:00:00 -0400
sg3-utils (1.45-0.1) unstable; urgency=low
diff --git a/doc/sg_dd.8 b/doc/sg_dd.8
index 90d707bc..b2d45874 100644
--- a/doc/sg_dd.8
+++ b/doc/sg_dd.8
@@ -242,6 +242,10 @@ traditional dd conversions (e.g. ASCII to EBCDIC). Recently added
conversions overlap somewhat with the flags so some conversions are
now supported by sg_dd.
.TP
+nocreat
+this conversion has the same effect as "oflag=nocreat", namely: \fIOFILE\fR
+must exist, it will not be created.
+.TP
noerror
this conversion is very close to "iflag=coe" and is treated as such. See
the "coe" flag. Note that an error on \fIOFILE\fR will stop the copy.
@@ -352,6 +356,16 @@ nocache
use posix_fadvise() to advise corresponding file there is no need to fill
the file buffer with recently read or written blocks.
.TP
+nocreat
+this flag is only active in \fIoflag=FLAGS\fR. If present then \fIOFILE\fR
+will be opened if it exists. If \fIOFILE\fR doesn't exist then an error
+is generated. Without this flag a regular (empty) file named \fIOFILE\fR
+will be created (and then filled). For production quality scripts where
+\fIOFILE\fR is a device node (e.g. '/dev/sdc') this flag is recommended.
+It guards against the remote possibility of 'dev/sdc' disappearing
+temporarily (e.g. a USB memory key removed) resulting in a large regular
+file called '/dev/sdc' being created.
+.TP
null
has no affect, just a placeholder.
.TP
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 532547be..7bf1afd0 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -84,7 +84,7 @@ fi
%{_libdir}/*.la
%changelog
-* Tue Sep 01 2020 - dgilbert at interlog dot com
+* Tue Oct 13 2020 - dgilbert at interlog dot com
- track t10 changes
* sg3_utils-1.46
diff --git a/src/sg_dd.c b/src/sg_dd.c
index a3e9022a..b20c6682 100644
--- a/src/sg_dd.c
+++ b/src/sg_dd.c
@@ -67,7 +67,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "6.19 20201008";
+static const char * version_str = "6.20 20201011";
#define ME "sg_dd: "
@@ -186,6 +186,7 @@ struct flags_t {
bool flock;
bool ff;
bool fua;
+ bool nocreat;
bool random;
bool sgio;
bool sparse;
@@ -425,11 +426,12 @@ dd_filetype_str(int ft, char * buff)
static void
usage()
{
- pr2serr("Usage: sg_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE] "
- "[iflag=FLAGS]\n"
- " [obs=BS] [of=OFILE] [oflag=FLAGS] "
- "[seek=SEEK] [skip=SKIP]\n"
- " [--dry-run] [--help] [--verbose] [--version]\n\n"
+ pr2serr("Usage: sg_dd [bs=BS] [conv=CONV] [count=COUNT] [ibs=BS] "
+ "[if=IFILE]\n"
+ " [iflag=FLAGS] [obs=BS] [of=OFILE] [oflag=FLAGS] "
+ "[seek=SEEK]\n"
+ " [skip=SKIP] [--dry-run] [--help] [--verbose] "
+ "[--version]\n\n"
" [blk_sgio=0|1] [bpt=BPT] [cdbsz=6|10|12|16] "
"[coe=0|1|2|3]\n"
" [coe_limit=CL] [dio=0|1] [odir=0|1] "
@@ -452,6 +454,9 @@ usage()
" coe_limit limit consecutive 'bad' blocks on reads to CL "
"times\n"
" when COE>1 (default: 0 which is no limit)\n"
+ " conv comma separated list from: [nocreat,noerror,"
+ "notrunc,\n"
+ " null,sparse,sync]\n"
" count number of blocks to copy (def: device size)\n"
" dio for direct IO, 1->attempt, 0->indirect IO "
"(def)\n"
@@ -473,7 +478,7 @@ usage()
" normal file or pipe\n"
" oflag comma separated list from: [append,coe,dio,"
"direct,dpo,\n"
- " dsync,excl,flock,fua,nocache,null,sgio,"
+ " dsync,excl,flock,fua,nocache,nocreat,null,sgio,"
"sparse]\n"
" retries retry sgio errors RETR times (def: 0)\n"
" seek block position to start writing to OFILE\n"
@@ -1277,6 +1282,8 @@ process_flags(const char * arg, struct flags_t * fp)
fp->fua = true;
else if (0 == strcmp(cp, "nocache"))
++fp->nocache;
+ else if (0 == strcmp(cp, "nocreat"))
+ fp->nocreat = true;
else if (0 == strcmp(cp, "null"))
;
else if (0 == strcmp(cp, "random"))
@@ -1314,31 +1321,19 @@ process_conv(const char * arg, struct flags_t * ifp, struct flags_t * ofp)
np = strchr(cp, ',');
if (np)
*np++ = '\0';
-#if 0
- if (0 == strcmp(cp, "fdatasync"))
- ++ofp->fdatasync;
- else if (0 == strcmp(cp, "fsync"))
- ++ofp->fsync;
-#endif
- if (0 == strcmp(cp, "noerror"))
+ if (0 == strcmp(cp, "nocreat"))
+ ofp->nocreat = true;
+ else if (0 == strcmp(cp, "noerror"))
++ifp->coe; /* will still fail on write error */
else if (0 == strcmp(cp, "notrunc"))
- ; /* this is the default action of ddpt so ignore */
+ ; /* this is the default action of sg_dd so ignore */
else if (0 == strcmp(cp, "null"))
;
-#if 0
- else if (0 == strcmp(cp, "sparing"))
- ++ofp->sparing;
-#endif
else if (0 == strcmp(cp, "sparse"))
ofp->sparse = true;
else if (0 == strcmp(cp, "sync"))
- ; /* dd(susv4): pad errored block(s) with zeros but ddpt does
+ ; /* dd(susv4): pad errored block(s) with zeros but sg_dd does
* that by default. Typical dd use: 'conv=noerror,sync' */
-#if 0
- else if (0 == strcmp(cp, "trunc"))
- ++ofp->trunc;
-#endif
else {
pr2serr("unrecognised flag: %s\n", cp);
return 1;
@@ -1549,7 +1544,9 @@ open_of(const char * outf, int64_t seek, int bpt, struct flags_t * ofp,
outfd = -1; /* don't bother opening */
else {
if (! (FT_RAW & *out_typep)) {
- flags = O_WRONLY | O_CREAT;
+ flags = O_WRONLY;
+ if (! ofp->nocreat)
+ flags = O_CREAT;
if (ofp->direct)
flags |= O_DIRECT;
if (ofp->excl)
diff --git a/testing/sg_mrq_dd.cpp b/testing/sg_mrq_dd.cpp
index 5cd9da49..f304eb51 100644
--- a/testing/sg_mrq_dd.cpp
+++ b/testing/sg_mrq_dd.cpp
@@ -30,7 +30,7 @@
*
*/
-static const char * version_str = "1.14 20201008";
+static const char * version_str = "1.15 20201012";
#define _XOPEN_SOURCE 600
#ifndef _GNU_SOURCE
@@ -180,6 +180,7 @@ struct flags_t {
bool fua;
bool masync; /* more async sg v4 driver fd flag */
bool no_dur;
+ bool nocreat;
bool order;
bool qhead;
bool qtail;
@@ -816,11 +817,11 @@ usage(int pg_num)
else if (pg_num > 1)
goto page2;
- pr2serr("Usage: sg_mrq_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE]"
- " [iflag=FLAGS]\n"
- " [obs=BS] [of=OFILE] [oflag=FLAGS] "
- "[seek=SEEK]\n"
- " [skip=SKIP] [--help] [--verify] "
+ pr2serr("Usage: sg_mrq_dd [bs=BS] [conv=CONV] [count=COUNT] [ibs=BS] "
+ "[if=IFILE]\n"
+ " [iflag=FLAGS] [obs=BS] [of=OFILE] "
+ "[oflag=FLAGS]\n"
+ " [seek=SEEK] [skip=SKIP] [--help] [--verify] "
"[--version]\n\n");
pr2serr(" [bpt=BPT] [cdbsz=6|10|12|16] [dio=0|1] "
"[elemsz_kb=EKB]\n"
@@ -838,6 +839,9 @@ usage(int pg_num)
"above) are:\n"
" bs must be device logical block size (default "
"512)\n"
+ " conv comma separated list from: [nocreat,noerror,"
+ "notrunc,\n"
+ " null,sync]\n"
" count number of blocks to copy (def: device size)\n"
" if file or device to read from (def: stdin)\n"
" iflag comma separated list from: [coe,dio,"
@@ -848,8 +852,8 @@ usage(int pg_num)
"N.B. different\n"
" from dd it defaults to stdout). If 'of=.' "
"uses /dev/null\n"
- " oflag comma separated list from: [append,<<list from "
- "iflag>>]\n"
+ " oflag comma separated list from: [append,nocreat,\n"
+ " <<list from iflag>>]\n"
" seek block position to start writing to OFILE\n"
" skip block position to start reading from IFILE\n"
" --help|-h output this usage message then exit\n"
@@ -928,6 +932,7 @@ page3:
" masync set 'more async' flag on this sg device\n"
" mmap setup mmap IO on IFILE or OFILE\n"
" mmap,mmap when used twice, doesn't call munmap()\n"
+ " nocreat will fail rather than create OFILE\n"
" nodur turns off command duration calculations\n"
" order require write ordering on sg->sg copy; only "
"for oflag\n"
@@ -3032,6 +3037,46 @@ sg_out_open(struct global_collection *clp, const char *outf, uint8_t **mmpp,
return fd;
}
+/* Process arguments given to 'conv=" option. Returns 0 on success,
+ * 1 on error. */
+static int
+process_conv(const char * arg, struct flags_t * ifp, struct flags_t * ofp)
+{
+ char buff[256];
+ char * cp;
+ char * np;
+
+ strncpy(buff, arg, sizeof(buff));
+ buff[sizeof(buff) - 1] = '\0';
+ if ('\0' == buff[0]) {
+ pr2serr("no conversions found\n");
+ return 1;
+ }
+ cp = buff;
+ do {
+ np = strchr(cp, ',');
+ if (np)
+ *np++ = '\0';
+ if (0 == strcmp(cp, "nocreat"))
+ ofp->nocreat = true;
+ else if (0 == strcmp(cp, "noerror"))
+ ifp->coe = true; /* will still fail on write error */
+ else if (0 == strcmp(cp, "notrunc"))
+ ; /* this is the default action of sg_dd so ignore */
+ else if (0 == strcmp(cp, "null"))
+ ;
+ else if (0 == strcmp(cp, "sync"))
+ ; /* dd(susv4): pad errored block(s) with zeros but sg_dd does
+ * that by default. Typical dd use: 'conv=noerror,sync' */
+ else {
+ pr2serr("unrecognised flag: %s\n", cp);
+ return 1;
+ }
+ cp = np;
+ } while (cp);
+ return 0;
+}
+
#define STR_SZ 1024
#define INOUTF_SZ 512
@@ -3087,6 +3132,11 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp,
/* not documented, for compat with sgh_dd */
clp->in_flags.coe = !! sg_get_num(buf);
clp->out_flags.coe = clp->in_flags.coe;
+ } else if (0 == strcmp(key, "conv")) {
+ if (process_conv(buf, &clp->in_flags, &clp->out_flags)) {
+ pr2serr("%s: bad argument to 'conv='\n", my_name);
+ return SG_LIB_SYNTAX_ERROR;
+ }
} else if (0 == strcmp(key, "count")) {
if (clp->count_given) {
pr2serr("second 'count=' argument detected, only one "
@@ -3664,14 +3714,14 @@ main(int argc, char * argv[])
clp->infd = STDIN_FILENO;
clp->outfd = STDOUT_FILENO;
if (clp->in_flags.ff) {
- ccp = "<0xff bytes>";
- cc2p = "ff";
+ ccp = "<0xff bytes>";
+ cc2p = "ff";
} else if (clp->in_flags.random) {
- ccp = "<random>";
- cc2p = "random";
+ ccp = "<random>";
+ cc2p = "random";
} else if (clp->in_flags.zero) {
- ccp = "<zero bytes>";
- cc2p = "00";
+ ccp = "<zero bytes>";
+ cc2p = "00";
}
if (ccp) {
if (inf[0]) {
@@ -3737,7 +3787,9 @@ main(int argc, char * argv[])
clp->outfd = -1; /* don't bother opening */
else {
if (FT_RAW != clp->out_type) {
- flags = O_WRONLY | O_CREAT;
+ flags = O_WRONLY;
+ if (! clp->out_flags.nocreat)
+ flags |= O_CREAT;
if (clp->out_flags.direct)
flags |= O_DIRECT;
if (clp->out_flags.excl)
diff --git a/testing/sgh_dd.cpp b/testing/sgh_dd.cpp
index 82d9869d..b7381f44 100644
--- a/testing/sgh_dd.cpp
+++ b/testing/sgh_dd.cpp
@@ -36,7 +36,7 @@
* renamed [20181221]
*/
-static const char * version_str = "1.94 20200927";
+static const char * version_str = "1.95 20201012";
#define _XOPEN_SOURCE 600
#ifndef _GNU_SOURCE
@@ -177,6 +177,7 @@ struct flags_t {
bool mrq_immed; /* mrq submit non-blocking */
bool mrq_svb; /* mrq shared_variable_block, for sg->sg copy */
bool no_dur;
+ bool nocreat;
bool noshare;
bool no_unshare; /* leave it for driver close/release */
bool no_waitq;
@@ -889,11 +890,11 @@ usage(int pg_num)
else if (pg_num > 1)
goto page2;
- pr2serr("Usage: sgh_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE]"
- " [iflag=FLAGS]\n"
- " [obs=BS] [of=OFILE] [oflag=FLAGS] "
- "[seek=SEEK] [skip=SKIP]\n"
- " [--help] [--version]\n\n");
+ pr2serr("Usage: sgh_dd [bs=BS] [conv=CONVS] [count=COUNT] [ibs=BS] "
+ "[if=IFILE]\n"
+ " [iflag=FLAGS] [obs=BS] [of=OFILE] [oflag=FLAGS] "
+ "[seek=SEEK]\n"
+ " [skip=SKIP] [--help] [--version]\n\n");
pr2serr(" [ae=AEN[,MAEN]] [bpt=BPT] [cdbsz=6|10|12|16] "
"[coe=0|1]\n"
" [dio=0|1] [elemsz_kb=EKB] [fail_mask=FM] "
@@ -908,6 +909,9 @@ usage(int pg_num)
" where the main options (shown in first group above) are:\n"
" bs must be device logical block size (default "
"512)\n"
+ " conv comma separated list from: [nocreat,noerror,"
+ "notrunc,\n"
+ " null,sync]\n"
" count number of blocks to copy (def: device size)\n"
" if file or device to read from (def: stdin)\n"
" iflag comma separated list from: [coe,defres,dio,"
@@ -1021,6 +1025,7 @@ page3:
" blocking)\n"
" mrq_svb if mrq and sg->sg copy, do shared_variable_"
"blocking\n"
+ " nocreat will fail rather than create OFILE\n"
" nodur turns off command duration calculations\n"
" no_waitq when non-blocking (async) don't use wait "
"queue\n"
@@ -3660,6 +3665,8 @@ process_flags(const char * arg, struct flags_t * fp)
fp->no_dur = true;
else if (0 == strcmp(cp, "no_dur"))
fp->no_dur = true;
+ else if (0 == strcmp(cp, "nocreat"))
+ fp->nocreat = true;
else if (0 == strcmp(cp, "noshare"))
fp->noshare = true;
else if (0 == strcmp(cp, "no_share"))
@@ -3784,6 +3791,46 @@ sg_out_open(struct global_collection *clp, const char *outf, uint8_t **mmpp,
return fd;
}
+/* Process arguments given to 'conv=" option. Returns 0 on success,
+ * 1 on error. */
+static int
+process_conv(const char * arg, struct flags_t * ifp, struct flags_t * ofp)
+{
+ char buff[256];
+ char * cp;
+ char * np;
+
+ strncpy(buff, arg, sizeof(buff));
+ buff[sizeof(buff) - 1] = '\0';
+ if ('\0' == buff[0]) {
+ pr2serr("no conversions found\n");
+ return 1;
+ }
+ cp = buff;
+ do {
+ np = strchr(cp, ',');
+ if (np)
+ *np++ = '\0';
+ if (0 == strcmp(cp, "nocreat"))
+ ofp->nocreat = true;
+ else if (0 == strcmp(cp, "noerror"))
+ ifp->coe = true; /* will still fail on write error */
+ else if (0 == strcmp(cp, "notrunc"))
+ ; /* this is the default action of sg_dd so ignore */
+ else if (0 == strcmp(cp, "null"))
+ ;
+ else if (0 == strcmp(cp, "sync"))
+ ; /* dd(susv4): pad errored block(s) with zeros but sg_dd does
+ * that by default. Typical dd use: 'conv=noerror,sync' */
+ else {
+ pr2serr("unrecognised flag: %s\n", cp);
+ return 1;
+ }
+ cp = np;
+ } while (cp);
+ return 0;
+}
+
#define STR_SZ 1024
#define INOUTF_SZ 512
@@ -3853,6 +3900,11 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp,
} else if (0 == strcmp(key, "coe")) {
clp->in_flags.coe = !! sg_get_num(buf);
clp->out_flags.coe = clp->in_flags.coe;
+ } else if (0 == strcmp(key, "conv")) {
+ if (process_conv(buf, &clp->in_flags, &clp->out_flags)) {
+ pr2serr("%s: bad argument to 'conv='\n", my_name);
+ return SG_LIB_SYNTAX_ERROR;
+ }
} else if (0 == strcmp(key, "count")) {
if (0 != strcmp("-1", buf)) {
dd_count = sg_get_llnum(buf);
@@ -4327,7 +4379,9 @@ main(int argc, char * argv[])
clp->outfd = -1; /* don't bother opening */
else {
if (FT_RAW != clp->out_type) {
- flags = O_WRONLY | O_CREAT;
+ flags = O_WRONLY;
+ if (! clp->out_flags.nocreat)
+ flags |= O_CREAT;
if (clp->out_flags.direct)
flags |= O_DIRECT;
if (clp->out_flags.excl)
@@ -4395,7 +4449,9 @@ main(int argc, char * argv[])
clp->out2fd = -1; /* don't bother opening */
else {
if (FT_RAW != clp->out2_type) {
- flags = O_WRONLY | O_CREAT;
+ flags = O_WRONLY;
+ if (! clp->out_flags.nocreat)
+ flags |= O_CREAT;
if (clp->out_flags.direct)
flags |= O_DIRECT;
if (clp->out_flags.excl)