aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2018-06-01 04:18:50 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2018-06-01 04:18:50 +0000
commit14a6fbe3500a5ead474126ded5e0f1df8dd88ade (patch)
tree319ae5568a3634b4d9a8e9614bd726704dbea28d
parent9188a48d4a76281c11cb75497cdff74b40662d4c (diff)
downloadsg3_utils-14a6fbe3500a5ead474126ded5e0f1df8dd88ade.tar.gz
expand SNTL; sg_dd: add --dry-run and --verbose options
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@776 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog4
-rw-r--r--lib/sg_pt_common.c90
-rw-r--r--lib/sg_pt_freebsd.c41
-rw-r--r--lib/sg_pt_linux_nvme.c37
-rw-r--r--lib/sg_pt_win32.c39
-rw-r--r--src/sg_dd.c83
6 files changed, 239 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index d9162191..7c2ba040 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@ 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.43 [20180530] [svn: r775]
+Changelog for sg3_utils-1.43 [20180531] [svn: r776]
- sg_write_x: where x can be normal, atomic, or(write),
same, scattered, or stream writes with 16 or 32 byte
cdbs (sbc4r04 for atomic, sbc4r11 for scattered)
@@ -83,6 +83,8 @@ Changelog for sg3_utils-1.43 [20180530] [svn: r775]
- sg_vpd: 3 party copy VPD page improvements
- fully implement Device constituents VPD page
- improve handling of unknown pages
+ - sg_dd: add --dry-run and --verbose options
+ - allow multiple short options (e.g. -dvv )
- sg_reassign+sg_write_same: fix ULONG_MAX problem
- sg_rdac: add sanity checks for -f=lun value
- sg_turs+sg_requests: make both accept '--num=NUM'
diff --git a/lib/sg_pt_common.c b/lib/sg_pt_common.c
index 23b6a358..8049f53d 100644
--- a/lib/sg_pt_common.c
+++ b/lib/sg_pt_common.c
@@ -29,7 +29,7 @@
#endif
-static const char * scsi_pt_version_str = "3.05 20180309";
+static const char * scsi_pt_version_str = "3.06 20180531";
@@ -230,6 +230,32 @@ resp_ctrl_m_pg(uint8_t *p, int pcontrol)
return sizeof(ctrl_m_pg);
}
+static uint8_t ctrl_ext_m_pg[] = {0x4a, 0x1, 0, 0x1c, 0, 0, 0x40, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, };
+
+/* Control Extension mode page [0xa,0x1] for mode_sense */
+static int
+resp_ctrl_ext_m_pg(uint8_t *p, int pcontrol)
+{
+ uint8_t ch_ctrl_ext_m_pg[] = {/* 0x4a, 0x1, 0, 0x1c, */ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, };
+ uint8_t d_ctrl_ext_m_pg[] = {0x4a, 0x1, 0, 0x1c, 0, 0, 0x40, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, };
+
+ memcpy(p, ctrl_ext_m_pg, sizeof(ctrl_ext_m_pg));
+ if (1 == pcontrol)
+ memcpy(p + 4, ch_ctrl_ext_m_pg, sizeof(ch_ctrl_ext_m_pg));
+ else if (2 == pcontrol)
+ memcpy(p, d_ctrl_ext_m_pg, sizeof(d_ctrl_ext_m_pg));
+ return sizeof(ctrl_ext_m_pg);
+}
+
static uint8_t iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x0};
/* Informational Exceptions control mode page for mode_sense */
@@ -333,26 +359,36 @@ sntl_resp_mode_sense10(const struct sg_sntl_dev_state_t * dsp,
offset += bd_len;
ap = arr + offset;
}
-
- if ((subpcode > 0x0) && (subpcode < 0xff)) {
- resp->asc = INVALID_FIELD_IN_CDB;
- resp->in_byte = 3;
- resp->in_bit = 255;
- goto err_out;
- }
bad_pcode = false;
switch (pcode) {
case 0x2: /* Disconnect-Reconnect page, all devices */
- len = resp_disconnect_pg(ap, pcontrol);
+ if (0x0 == subpcode)
+ len = resp_disconnect_pg(ap, pcontrol);
+ else {
+ len = 0;
+ bad_pcode = true;
+ }
offset += len;
break;
case 0xa: /* Control Mode page, all devices */
- len = resp_ctrl_m_pg(ap, pcontrol);
+ if (0x0 == subpcode)
+ len = resp_ctrl_m_pg(ap, pcontrol);
+ else if (0x1 == subpcode)
+ len = resp_ctrl_ext_m_pg(ap, pcontrol);
+ else {
+ len = 0;
+ bad_pcode = true;
+ }
offset += len;
break;
case 0x1c: /* Informational Exceptions Mode page, all devices */
- len = resp_iec_m_pg(ap, pcontrol);
+ if (0x0 == subpcode)
+ len = resp_iec_m_pg(ap, pcontrol);
+ else {
+ len = 0;
+ bad_pcode = true;
+ }
offset += len;
break;
case 0x3f: /* Read all Mode pages */
@@ -360,6 +396,8 @@ sntl_resp_mode_sense10(const struct sg_sntl_dev_state_t * dsp,
len = 0;
len = resp_disconnect_pg(ap + len, pcontrol);
len += resp_ctrl_m_pg(ap + len, pcontrol);
+ if (0xff == subpcode)
+ len += resp_ctrl_ext_m_pg(ap + len, pcontrol);
len += resp_iec_m_pg(ap + len, pcontrol);
len += resp_vs_ua_m_pg(ap + len, pcontrol);
offset += len;
@@ -371,6 +409,7 @@ sntl_resp_mode_sense10(const struct sg_sntl_dev_state_t * dsp,
}
break;
case 0x0: /* Vendor specific "Unit Attention" mode page */
+ /* all sub-page codes ?? */
len = resp_vs_ua_m_pg(ap, pcontrol);
offset += len;
break; /* vendor is "NVMe " (from INQUIRY field) */
@@ -406,6 +445,7 @@ sntl_resp_mode_select10(struct sg_sntl_dev_state_t * dsp,
struct sg_sntl_result_t * resp)
{
int pf, sp, ps, md_len, bd_len, off, spf, pg_len, rlen, param_len, mpage;
+ int sub_mpage;
uint8_t arr[SDEBUG_MAX_MSELECT_SZ];
memset(resp, 0, sizeof(*resp));
@@ -448,24 +488,31 @@ sntl_resp_mode_select10(struct sg_sntl_dev_state_t * dsp,
spf = !!(arr[off] & 0x40);
pg_len = spf ? (sg_get_unaligned_be16(arr + off + 2) + 4) :
(arr[off + 1] + 2);
+ sub_mpage = spf ? arr[off + 1] : 0;
if ((pg_len + off) > param_len) {
resp->asc = PARAMETER_LIST_LENGTH_ERR;
goto err_out;
}
switch (mpage) {
case 0xa: /* Control Mode page */
- if (ctrl_m_pg[1] == arr[off + 1]) {
- memcpy(ctrl_m_pg + 2, arr + off + 2,
- sizeof(ctrl_m_pg) - 2);
- dsp->descriptor_sense = !!(ctrl_m_pg[2] & 0x4);
+ if (0x0 == sub_mpage) {
+ if (ctrl_m_pg[1] == arr[off + 1]) {
+ memcpy(ctrl_m_pg + 2, arr + off + 2,
+ sizeof(ctrl_m_pg) - 2);
+ dsp->descriptor_sense = !!(ctrl_m_pg[2] & 0x4);
+ break;
+ }
}
- break;
- case 0x1c: /* Informational Exceptions Mode page */
- if (iec_m_pg[1] == arr[off + 1]) {
- memcpy(iec_m_pg + 2, arr + off + 2,
- sizeof(iec_m_pg) - 2);
+ goto def_case;
+ case 0x1c: /* Informational Exceptions Mode page (SBC) */
+ if (0x0 == sub_mpage) {
+ if (iec_m_pg[1] == arr[off + 1]) {
+ memcpy(iec_m_pg + 2, arr + off + 2,
+ sizeof(iec_m_pg) - 2);
+ break;
+ }
}
- break;
+ goto def_case;
case 0x0: /* Vendor specific "Unit Attention" mode page */
if (vs_ua_m_pg[1] == arr[off + 1]) {
memcpy(vs_ua_m_pg + 2, arr + off + 2,
@@ -474,6 +521,7 @@ sntl_resp_mode_select10(struct sg_sntl_dev_state_t * dsp,
}
break;
default:
+def_case:
resp->asc = INVALID_FIELD_IN_PARAM_LIST;
resp->in_byte = off;
resp->in_bit = 5;
diff --git a/lib/sg_pt_freebsd.c b/lib/sg_pt_freebsd.c
index 7fec9b64..491d1305 100644
--- a/lib/sg_pt_freebsd.c
+++ b/lib/sg_pt_freebsd.c
@@ -5,7 +5,7 @@
* license that can be found in the BSD_LICENSE file.
*/
-/* sg_pt_freebsd version 1.28 20180526 */
+/* sg_pt_freebsd version 1.29 20180531 */
#include <stdio.h>
#include <stdlib.h>
@@ -895,7 +895,7 @@ pt_device_is_nvme(const struct sg_pt_base * vp)
fdc_p = get_fdc_cp(ptp);
if (NULL == fdc_p) {
- pr2serr("%s: unable to find fdc_p\n", __func__);
+ pr2ws("%s: unable to find fdc_p\n", __func__);
errno = ENODEV;
return false;
}
@@ -1002,7 +1002,6 @@ build_sense_buffer(bool desc, uint8_t *buf, uint8_t skey, uint8_t asc,
}
}
-/* Set in_bit to -1 to indicate no bit position of invalid field */
static void
mk_sense_asc_ascq(struct sg_pt_freebsd_scsi * ptp, int sk, int asc, int ascq,
int vb)
@@ -1099,7 +1098,8 @@ mk_sense_invalid_fld(struct sg_pt_freebsd_scsi * ptp, bool in_cdb,
memcpy(sbp + 15, sks, 3);
if (vb > 3)
pr2ws("%s: [sense_key,asc,ascq]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
- __func__, asc, in_cdb ? 'C' : 'D', in_byte, in_bit);
+ __func__, asc, in_cdb ? 'C' : 'D', in_byte,
+ ((in_bit > 0) ? (0x7 & in_bit) : 0));
}
/* Does actual ioctl(NVME_PASSTHROUGH_CMD). Returns 0 on success; negative
@@ -1280,19 +1280,22 @@ sntl_inq(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int vb)
case 0: /* Supported VPD pages VPD page */
/* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
inq_dout[1] = pg_cd;
- n = 8;
+ n = 11;
sg_put_unaligned_be16(n - 4, inq_dout + 2);
inq_dout[4] = 0x0;
inq_dout[5] = 0x80;
inq_dout[6] = 0x83;
- inq_dout[n - 1] = SG_NVME_VPD_NICR; /* 0xde */
+ inq_dout[7] = 0x86;
+ inq_dout[8] = 0x87;
+ inq_dout[9] = 0x92;
+ inq_dout[n - 1] = SG_NVME_VPD_NICR; /* last VPD number */
break;
case 0x80: /* Serial number VPD page */
/* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
inq_dout[1] = pg_cd;
- sg_put_unaligned_be16(20, inq_dout + 2);
- memcpy(inq_dout + 4, fdc_p->nvme_id_ctlp + 4, 20); /* SN */
n = 24;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ memcpy(inq_dout + 4, ptp->nvme_id_ctlp + 4, 20); /* SN */
break;
case 0x83: /* Device identification VPD page */
if ((fdc_p->nsid > 0) && (fdc_p->nsid < SG_NVME_BROADCAST_NSID)) {
@@ -1331,6 +1334,28 @@ sntl_inq(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int vb)
nvme_id_ns = NULL;
}
break;
+ case 0x86: /* Extended INQUIRY (per SFS SPC Discovery 2016) */
+ inq_dout[1] = pg_cd;
+ n = 64;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ inq_dout[5] = 0x1; /* SIMPSUP=1 */
+ inq_dout[7] = 0x1; /* LUICLR=1 */
+ inq_dout[13] = 0x40; /* max supported sense data length */
+ break;
+ case 0x87: /* Mode page policy (per SFS SPC Discovery 2016) */
+ inq_dout[1] = pg_cd;
+ n = 8;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ inq_dout[4] = 0x3f; /* all mode pages */
+ inq_dout[5] = 0xff; /* and their sub-pages */
+ inq_dout[6] = 0x80; /* MLUS=1, policy=shared */
+ break;
+ case 0x92: /* SCSI Feature set: only SPC Discovery 2016 */
+ inq_dout[1] = pg_cd;
+ n = 10;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ inq_dout[9] = 0x1; /* SFS SPC Discovery 2016 */
+ break;
case SG_NVME_VPD_NICR: /* 0xde */
inq_dout[1] = pg_cd;
sg_put_unaligned_be16((16 + 4096) - 4, inq_dout + 2);
diff --git a/lib/sg_pt_linux_nvme.c b/lib/sg_pt_linux_nvme.c
index e547e95d..f78600af 100644
--- a/lib/sg_pt_linux_nvme.c
+++ b/lib/sg_pt_linux_nvme.c
@@ -188,7 +188,6 @@ build_sense_buffer(bool desc, uint8_t *buf, uint8_t skey, uint8_t asc,
}
}
-/* Set in_bit to -1 to indicate no bit position of invalid field */
static void
mk_sense_asc_ascq(struct sg_pt_linux_scsi * ptp, int sk, int asc, int ascq,
int vb)
@@ -285,7 +284,8 @@ mk_sense_invalid_fld(struct sg_pt_linux_scsi * ptp, bool in_cdb, int in_byte,
memcpy(sbp + 15, sks, 3);
if (vb > 3)
pr2ws("%s: [sense_key,asc,ascq]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
- __func__, asc, in_cdb ? 'C' : 'D', in_byte, in_bit);
+ __func__, asc, in_cdb ? 'C' : 'D', in_byte,
+ ((in_bit > 0) ? (0x7 & in_bit) : 0));
}
/* Returns 0 for success. Returns SG_LIB_NVME_STATUS if there is non-zero
@@ -504,19 +504,22 @@ sntl_inq(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs,
case 0:
/* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
inq_dout[1] = pg_cd;
- n = 8;
+ n = 11;
sg_put_unaligned_be16(n - 4, inq_dout + 2);
inq_dout[4] = 0x0;
inq_dout[5] = 0x80;
inq_dout[6] = 0x83;
+ inq_dout[7] = 0x86;
+ inq_dout[8] = 0x87;
+ inq_dout[9] = 0x92;
inq_dout[n - 1] = SG_NVME_VPD_NICR; /* last VPD number */
break;
case 0x80:
/* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
inq_dout[1] = pg_cd;
- sg_put_unaligned_be16(20, inq_dout + 2);
- memcpy(inq_dout + 4, ptp->nvme_id_ctlp + 4, 20); /* SN */
n = 24;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ memcpy(inq_dout + 4, ptp->nvme_id_ctlp + 4, 20); /* SN */
break;
case 0x83:
if ((ptp->nvme_nsid > 0) &&
@@ -552,7 +555,29 @@ sntl_inq(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs,
nvme_id_ns = NULL;
}
break;
- case SG_NVME_VPD_NICR: /* 0xde */
+ case 0x86: /* Extended INQUIRY (per SFS SPC Discovery 2016) */
+ inq_dout[1] = pg_cd;
+ n = 64;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ inq_dout[5] = 0x1; /* SIMPSUP=1 */
+ inq_dout[7] = 0x1; /* LUICLR=1 */
+ inq_dout[13] = 0x40; /* max supported sense data length */
+ break;
+ case 0x87: /* Mode page policy (per SFS SPC Discovery 2016) */
+ inq_dout[1] = pg_cd;
+ n = 8;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ inq_dout[4] = 0x3f; /* all mode pages */
+ inq_dout[5] = 0xff; /* and their sub-pages */
+ inq_dout[6] = 0x80; /* MLUS=1, policy=shared */
+ break;
+ case 0x92: /* SCSI Feature set: only SPC Discovery 2016 */
+ inq_dout[1] = pg_cd;
+ n = 10;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ inq_dout[9] = 0x1; /* SFS SPC Discovery 2016 */
+ break;
+ case SG_NVME_VPD_NICR: /* 0xde (vendor (sg3_utils) specific) */
inq_dout[1] = pg_cd;
sg_put_unaligned_be16((16 + 4096) - 4, inq_dout + 2);
n = 16 + 4096;
diff --git a/lib/sg_pt_win32.c b/lib/sg_pt_win32.c
index c4c84f21..1d218b2e 100644
--- a/lib/sg_pt_win32.c
+++ b/lib/sg_pt_win32.c
@@ -5,7 +5,7 @@
* license that can be found in the BSD_LICENSE file.
*/
-/* sg_pt_win32 version 1.26 20180526 */
+/* sg_pt_win32 version 1.27 20180531 */
#include <stdio.h>
#include <stdlib.h>
@@ -1399,7 +1399,6 @@ build_sense_buffer(bool desc, uint8_t *buf, uint8_t skey, uint8_t asc,
}
}
-/* Set in_bit to -1 to indicate no bit position of invalid field */
static void
mk_sense_asc_ascq(struct sg_pt_win32_scsi * psp, int sk, int asc, int ascq,
int vb)
@@ -1501,7 +1500,8 @@ mk_sense_invalid_fld(struct sg_pt_win32_scsi * psp, bool in_cdb, int in_byte,
memcpy(sbp + 15, sks, 3);
if (vb > 3)
pr2ws("%s: [sense_key,asc,ascq]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
- __func__, asc, in_cdb ? 'C' : 'D', in_byte, in_bit);
+ __func__, asc, in_cdb ? 'C' : 'D', in_byte,
+ ((in_bit > 0) ? (0x7 & in_bit) : 0));
}
#if W10_NVME_NON_PASSTHRU /* W10 and later, no real pass-through ?? */
@@ -2244,19 +2244,22 @@ sntl_inq(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
case 0:
/* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
inq_dout[1] = pg_cd;
- n = 8;
+ n = 11;
sg_put_unaligned_be16(n - 4, inq_dout + 2);
inq_dout[4] = 0x0;
inq_dout[5] = 0x80;
inq_dout[6] = 0x83;
- inq_dout[n - 1] = SG_NVME_VPD_NICR; /* 0xde last VPD number */
+ inq_dout[7] = 0x86;
+ inq_dout[8] = 0x87;
+ inq_dout[9] = 0x92;
+ inq_dout[n - 1] = SG_NVME_VPD_NICR; /* last VPD number */
break;
case 0x80:
/* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
inq_dout[1] = pg_cd;
- sg_put_unaligned_be16(20, inq_dout + 2);
- memcpy(inq_dout + 4, psp->nvme_id_ctlp + 4, 20); /* SN */
n = 24;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ memcpy(inq_dout + 4, ptp->nvme_id_ctlp + 4, 20); /* SN */
break;
case 0x83:
if ((psp->nvme_nsid > 0) &&
@@ -2294,6 +2297,28 @@ sntl_inq(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
nvme_id_ns = NULL;
}
break;
+ case 0x86: /* Extended INQUIRY (per SFS SPC Discovery 2016) */
+ inq_dout[1] = pg_cd;
+ n = 64;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ inq_dout[5] = 0x1; /* SIMPSUP=1 */
+ inq_dout[7] = 0x1; /* LUICLR=1 */
+ inq_dout[13] = 0x40; /* max supported sense data length */
+ break;
+ case 0x87: /* Mode page policy (per SFS SPC Discovery 2016) */
+ inq_dout[1] = pg_cd;
+ n = 8;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ inq_dout[4] = 0x3f; /* all mode pages */
+ inq_dout[5] = 0xff; /* and their sub-pages */
+ inq_dout[6] = 0x80; /* MLUS=1, policy=shared */
+ break;
+ case 0x92: /* SCSI Feature set: only SPC Discovery 2016 */
+ inq_dout[1] = pg_cd;
+ n = 10;
+ sg_put_unaligned_be16(n - 4, inq_dout + 2);
+ inq_dout[9] = 0x1; /* SFS SPC Discovery 2016 */
+ break;
case SG_NVME_VPD_NICR: /* 0xde */
inq_dout[1] = pg_cd;
sg_put_unaligned_be16((16 + 4096) - 4, inq_dout + 2);
diff --git a/src/sg_dd.c b/src/sg_dd.c
index d95b3ad1..3515b665 100644
--- a/src/sg_dd.c
+++ b/src/sg_dd.c
@@ -62,7 +62,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "5.99 20180522";
+static const char * version_str = "6.00 20180531";
#define ME "sg_dd: "
@@ -135,6 +135,7 @@ static int recovered_errs = 0;
static int unrecovered_errs = 0;
static int read_longs = 0;
static int num_retries = 0;
+static int dry_run = 0;
static bool do_time = false;
static bool start_tm_valid = false;
@@ -351,7 +352,7 @@ usage()
"[iflag=FLAGS]\n"
" [obs=BS] [of=OFILE] [oflag=FLAGS] "
"[seek=SEEK] [skip=SKIP]\n"
- " [--help] [--version]\n\n"
+ " [--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] "
@@ -404,7 +405,10 @@ usage()
"throughput\n"
" verbose 0->quiet(def), 1->some noise, 2->more noise, "
"etc\n"
+ " --dry-run do preparation but bypass copy (or read)\n"
" --help print out this usage message then exit\n"
+ " --verbose same as 'verbose=1', can be used multiple "
+ "times\n"
" --version print version information then exit\n\n"
"copy from IFILE to OFILE, similar to dd command; "
"specialized for SCSI devices\n");
@@ -1467,6 +1471,20 @@ other_err:
return -SG_LIB_CAT_OTHER;
}
+/* Returns the number of times 'ch' is found in string 's' given the
+ * string's length. */
+static int
+num_chs_in_str(const char * s, int slen, int ch)
+{
+ int res = 0;
+
+ while (--slen >= 0) {
+ if (ch == s[slen])
+ ++res;
+ }
+ return res;
+}
+
int
main(int argc, char * argv[])
@@ -1477,7 +1495,7 @@ main(int argc, char * argv[])
bool do_sync = false;
bool penult_sparse_skip = false;
bool sparse_skip = false;
- int res, k, t, buf_sz, blocks_per, infd, outfd, out2fd;
+ int res, k, n, t, buf_sz, blocks_per, infd, outfd, out2fd, keylen;
int retries_tmp, blks_read, bytes_read, bytes_of2, bytes_of;
int in_sect_sz, out_sect_sz;
int blocks = 0;
@@ -1526,6 +1544,7 @@ main(int argc, char * argv[])
buf++;
if (*buf)
*buf++ = '\0';
+ keylen = strlen(key);
if (0 == strncmp(key, "app", 3)) {
iflag.append = !! sg_get_num(buf);
oflag.append = iflag.append;
@@ -1541,6 +1560,9 @@ main(int argc, char * argv[])
bpt_given = true;
} else if (0 == strcmp(key, "bs")) {
blk_sz = sg_get_num(buf);
+ bpt_given = true;
+ } else if (0 == strcmp(key, "bs")) {
+ blk_sz = sg_get_num(buf);
if (-1 == blk_sz) {
pr2serr(ME "bad argument to 'bs='\n");
return SG_LIB_SYNTAX_ERROR;
@@ -1638,13 +1660,37 @@ main(int argc, char * argv[])
do_time = !! sg_get_num(buf);
else if (0 == strncmp(key, "verb", 4))
verbose = sg_get_num(buf);
- else if ((0 == strncmp(key, "--help", 7)) ||
- (0 == strncmp(key, "-h", 2)) ||
+ else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) {
+ res = 0;
+ n = num_chs_in_str(key + 1, keylen - 1, 'd');
+ dry_run += n;
+ res += n;
+ n = num_chs_in_str(key + 1, keylen - 1, 'h');
+ if (n > 0) {
+ usage();
+ return 0;
+ }
+ n = num_chs_in_str(key + 1, keylen - 1, 'v');
+ verbose += n;
+ res += n;
+ n = num_chs_in_str(key + 1, keylen - 1, 'V');
+ if (n > 0) {
+ pr2serr(ME "%s\n", version_str);
+ return 0;
+ }
+ if (res < (keylen - 1)) {
+ pr2serr("Unrecognised short option in '%s', try '--help'\n",
+ key);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if ((0 == strncmp(key, "--dry-run", 9)) ||
+ (0 == strncmp(key, "--dry_run", 9)))
+ ++dry_run;
+ else if ((0 == strncmp(key, "--help", 6)) ||
(0 == strcmp(key, "-?"))) {
usage();
return 0;
- } else if ((0 == strncmp(key, "--vers", 6)) ||
- (0 == strcmp(key, "-V"))) {
+ } else if (0 == strncmp(key, "--vers", 6)) {
pr2serr(ME "%s\n", version_str);
return 0;
} else {
@@ -1840,13 +1886,13 @@ main(int argc, char * argv[])
if (iflag.dio || iflag.direct || oflag.direct || (FT_RAW & in_type) ||
(FT_RAW & out_type)) { /* want heap buffer aligned to page_size */
- wrkPos = sg_memalign(blk_sz * bpt, 0, &wrkBuff, verbose > 3);
+ wrkPos = sg_memalign(blk_sz * bpt, 0, &wrkBuff, false);
if (NULL == wrkPos) {
pr2serr("sg_memalign: error, out of memory?\n");
return sg_convert_errno(ENOMEM);
}
} else {
- wrkPos = sg_memalign(blk_sz * bpt, 0, &wrkBuff, verbose > 3);
+ wrkPos = sg_memalign(blk_sz * bpt, 0, &wrkBuff, false);
if (0 == wrkPos) {
pr2serr("Not enough user memory\n");
return sg_convert_errno(ENOMEM);
@@ -1866,6 +1912,11 @@ main(int argc, char * argv[])
}
req_count = dd_count;
+ if (dry_run > 0) {
+ pr2serr("Since --dry-run option given, bypassing copy\n");
+ goto bypass_copy;
+ }
+
/* <<< main loop that does the copy >>> */
while (dd_count > 0) {
bytes_read = 0;
@@ -2127,6 +2178,7 @@ main(int argc, char * argv[])
skip += blocks;
seek += blocks;
} /* end of main loop that does the copy ... */
+
if (ret && penult_sparse_skip && (penult_blocks > 0)) {
/* if error and skipped last output due to sparse ... */
if ((FT_SG & out_type) || (FT_DEV_NULL & out_type))
@@ -2147,9 +2199,6 @@ main(int argc, char * argv[])
}
}
- if (do_time)
- calc_duration_throughput(false);
-
if (do_sync) {
if (FT_SG & out_type) {
pr2serr(">> Synchronizing cache on %s\n", outf);
@@ -2163,6 +2212,11 @@ main(int argc, char * argv[])
pr2serr("Unable to synchronize cache\n");
}
}
+
+bypass_copy:
+ if (do_time)
+ calc_duration_throughput(false);
+
free(wrkBuff);
if (free_zeros_buff)
free(free_zeros_buff);
@@ -2170,6 +2224,9 @@ main(int argc, char * argv[])
close(infd);
if (! ((STDOUT_FILENO == outfd) || (FT_DEV_NULL & out_type)))
close(outfd);
+ if (dry_run > 0)
+ goto bypass2;
+
if (0 != dd_count) {
pr2serr("Some error occurred,");
if (0 == ret)
@@ -2193,5 +2250,7 @@ main(int argc, char * argv[])
}
if (sum_of_resids)
pr2serr(">> Non-zero sum of residual counts=%d\n", sum_of_resids);
+
+bypass2:
return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}