aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--include/sg_lib.h2
-rw-r--r--include/sg_pt_nvme.h14
-rw-r--r--lib/sg_lib.c2
-rw-r--r--lib/sg_pt_common.c10
-rw-r--r--lib/sg_pt_freebsd.c8
-rw-r--r--lib/sg_pt_linux_nvme.c6
-rw-r--r--lib/sg_pt_win32.c6
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.in2
-rw-r--r--src/sg_vpd.c6
-rw-r--r--testing/sg_tst_nvme.c2
-rw-r--r--testing/sgh_dd.c94
-rw-r--r--utils/hxascdmp.113
-rw-r--r--utils/hxascdmp.c170
15 files changed, 274 insertions, 68 deletions
diff --git a/ChangeLog b/ChangeLog
index 815fed67..fbd77fd1 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.45 [20190206] [svn: r810]
+Changelog for sg3_utils-1.45 [20190210] [svn: r811]
- sg_ses: bug: --page= being overridden when --control
and --data= also given; fix
- sg_opcodes: expand MLU (spc5r20)
@@ -28,6 +28,9 @@ Changelog for sg3_utils-1.45 [20190206] [svn: r810]
- testing/sgh_dd: rename of sgs_dd to avoid ...
- testing/sgs_dd: back from archive, for testing
SIGPOLL (SIGIO) and realtime (RT) signals
+ - sg_pt: add sg_get_opcode_translation() to replace
+ global pointer to array: sg_opcode_info_arr[]
+ - utils/hxascdmp: add -o=<offset> option
- sg_io_linux (sg_lib): add sg_linux_sense_print()
- sg_pt_linux: uses sg v4 interface if sg driver
>= 4.0.0 . Force sg v3 always by building with
diff --git a/include/sg_lib.h b/include/sg_lib.h
index 9688991d..80c536c1 100644
--- a/include/sg_lib.h
+++ b/include/sg_lib.h
@@ -278,7 +278,7 @@ int sg_get_designation_descriptor_str(const char * leadin,
* bytes and returns the number of bytes actually written to 'b' but doesn't
* count the trailing null character it always appends (if blen > 0). 'lip'
* is lead-in string (on each line) than may be NULL. skip_prefix avoids
- * outputing ' Locally assigned UUID: ' before the UUID. */
+ * outputting: ' Locally assigned UUID: ' before the UUID. */
int sg_t10_uuid_desig2str(const uint8_t * dp, int dlen, int c_set,
bool do_long, bool skip_prefix,
const char * lip, int blen, char * b);
diff --git a/include/sg_pt_nvme.h b/include/sg_pt_nvme.h
index daca8fce..590b4de9 100644
--- a/include/sg_pt_nvme.h
+++ b/include/sg_pt_nvme.h
@@ -2,7 +2,7 @@
#define SG_PT_NVME_H
/*
- * Copyright (c) 2017-2018 Douglas Gilbert.
+ * Copyright (c) 2017-2019 Douglas Gilbert.
* All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the BSD_LICENSE file.
@@ -29,9 +29,9 @@ extern "C" {
* are exceptions, for example the EUI-64 identifiers in the Admin Identify
* response are big endian.
*
- * Code online (e.g. nvme-cli at github.com) seems to like packed strcutures,
- * the author prefers byte offset plus a range of unaligned integer builders
- * such as those in sg_unaligned.h .
+ * Code online (e.g. nvme-cli at github.com) seems to favour packed
+ * structures, while the author prefers byte offset plus a range of unaligned
+ * integer builders such as those in sg_unaligned.h .
*/
#ifdef __GNUC__
@@ -183,8 +183,6 @@ struct sg_opcode_info_t {
/* Vendor specific (sg3_utils) VPD pages */
#define SG_NVME_VPD_NICR 0xde /* NVME Identify controller response */
-extern struct sg_opcode_info_t sg_opcode_info_arr[];
-
/* Given the NVMe Identify Controller response and optionally the NVMe
* Identify Namespace response (NULL otherwise), generate the SCSI VPD
@@ -213,6 +211,10 @@ int sntl_resp_mode_select10(struct sg_sntl_dev_state_t * dsp,
const uint8_t * cdbp, const uint8_t * dop,
int do_len, struct sg_sntl_result_t * resp);
+/* Returns pointer to array of struct sg_opcode_info_t of SCSI commands
+ * translated to NVMe. */
+const struct sg_opcode_info_t * sg_get_opcode_translation(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index 79783974..eb74aadc 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -763,7 +763,7 @@ sg_get_desig_type_str(int val)
* bytes and returns the number of bytes actually written to 'b' but doesn't
* count the trailing null character it always appends (if blen > 0). 'lip'
* is lead-in string (on each line) than may be NULL. skip_prefix avoids
- * outputing ' Locally assigned UUID: ' before the UUID. */
+ * outputting: ' Locally assigned UUID: ' before the UUID. */
int
sg_t10_uuid_desig2str(const uint8_t *dp, int dlen, int c_set, bool do_long,
bool skip_prefix, const char * lip /* lead-in */,
diff --git a/lib/sg_pt_common.c b/lib/sg_pt_common.c
index 48bf4b2e..242e4774 100644
--- a/lib/sg_pt_common.c
+++ b/lib/sg_pt_common.c
@@ -64,7 +64,7 @@ static const char * nvme_scsi_vendor_str = "NVMe ";
#define F_INV_OP 0x200
/* Table of SCSI operation code (opcodes) supported by SNTL */
-struct sg_opcode_info_t sg_opcode_info_arr[] =
+static struct sg_opcode_info_t sg_opcode_info_arr[] =
{
{0x0, 0, 0, {6, /* TEST UNIT READY */
0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
@@ -92,7 +92,13 @@ struct sg_opcode_info_t sg_opcode_info_arr[] =
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
};
-
+/* Returns pointer to array of struct sg_opcode_info_t of SCSI commands
+ * translated to NVMe. */
+const struct sg_opcode_info_t *
+sg_get_opcode_translation(void)
+{
+ return sg_opcode_info_arr;
+}
/* Given the NVMe Identify controller response and optionally the NVMe
* Identify namespace response (NULL otherwise), generate the SCSI VPD
diff --git a/lib/sg_pt_freebsd.c b/lib/sg_pt_freebsd.c
index 596c77aa..a36b45b5 100644
--- a/lib/sg_pt_freebsd.c
+++ b/lib/sg_pt_freebsd.c
@@ -7,7 +7,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
-/* sg_pt_freebsd version 1.34 20190113 */
+/* sg_pt_freebsd version 1.35 20190210 */
#include <stdio.h>
#include <stdlib.h>
@@ -892,7 +892,7 @@ get_scsi_pt_duration_ms(const struct sg_pt_base * vp __attribute__ ((unused)))
/* If not available return 0 otherwise return number of nanoseconds that the
* lower layers (and hardware) took to execute the command just completed. */
-uint64_t
+uint64_t
get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused)))
{
return 0;
@@ -1976,7 +1976,7 @@ sntl_rep_opcodes(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
case 0: /* all commands */
count = 0;
bump = rctd ? 20 : 8;
- for (offset = 4, oip = sg_opcode_info_arr;
+ for (offset = 4, oip = sg_get_opcode_translation();
(oip->flags != 0xffff) && (offset < a_len); ++oip) {
if (F_INV_OP & oip->flags)
continue;
@@ -1997,7 +1997,7 @@ sntl_rep_opcodes(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
case 1: /* one command: opcode only */
case 2: /* one command: opcode plus service action */
case 3: /* one command: if sa==0 then opcode only else opcode+sa */
- for (oip = sg_opcode_info_arr; oip->flags != 0xffff; ++oip) {
+ for (oip = sg_get_opcode_translation(); oip->flags != 0xffff; ++oip) {
if ((req_opcode == oip->opcode) && (req_sa == oip->sa))
break;
}
diff --git a/lib/sg_pt_linux_nvme.c b/lib/sg_pt_linux_nvme.c
index 227af330..2309a794 100644
--- a/lib/sg_pt_linux_nvme.c
+++ b/lib/sg_pt_linux_nvme.c
@@ -41,7 +41,7 @@
* MA 02110-1301, USA.
*/
-/* sg_pt_linux_nvme version 1.06 20190113 */
+/* sg_pt_linux_nvme version 1.07 20190210 */
/* This file contains a small "SPC-only" SNTL to support the SES pass-through
* of SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS through NVME-MI
@@ -1046,7 +1046,7 @@ sntl_rep_opcodes(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
case 0: /* all commands */
count = 0;
bump = rctd ? 20 : 8;
- for (offset = 4, oip = sg_opcode_info_arr;
+ for (offset = 4, oip = sg_get_opcode_translation();
(oip->flags != 0xffff) && (offset < a_len); ++oip) {
if (F_INV_OP & oip->flags)
continue;
@@ -1067,7 +1067,7 @@ sntl_rep_opcodes(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
case 1: /* one command: opcode only */
case 2: /* one command: opcode plus service action */
case 3: /* one command: if sa==0 then opcode only else opcode+sa */
- for (oip = sg_opcode_info_arr; oip->flags != 0xffff; ++oip) {
+ for (oip = sg_get_opcode_translation(); oip->flags != 0xffff; ++oip) {
if ((req_opcode == oip->opcode) && (req_sa == oip->sa))
break;
}
diff --git a/lib/sg_pt_win32.c b/lib/sg_pt_win32.c
index 65e3f2b9..41295fc6 100644
--- a/lib/sg_pt_win32.c
+++ b/lib/sg_pt_win32.c
@@ -7,7 +7,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
-/* sg_pt_win32 version 1.29 20190111 */
+/* sg_pt_win32 version 1.30 20190210 */
#include <stdio.h>
#include <stdlib.h>
@@ -2878,7 +2878,7 @@ sntl_rep_opcodes(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
case 0: /* all commands */
count = 0;
bump = rctd ? 20 : 8;
- for (offset = 4, oip = sg_opcode_info_arr;
+ for (offset = 4, oip = sg_get_opcode_translation();
(oip->flags != 0xffff) && (offset < a_len); ++oip) {
if (F_INV_OP & oip->flags)
continue;
@@ -2899,7 +2899,7 @@ sntl_rep_opcodes(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
case 1: /* one command: opcode only */
case 2: /* one command: opcode plus service action */
case 3: /* one command: if sa==0 then opcode only else opcode+sa */
- for (oip = sg_opcode_info_arr; oip->flags != 0xffff; ++oip) {
+ for (oip = sg_get_opcode_translation(); oip->flags != 0xffff; ++oip) {
if ((req_opcode == oip->opcode) && (req_sa == oip->sa))
break;
}
diff --git a/src/Makefile.am b/src/Makefile.am
index 881cf296..0eba680b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -170,7 +170,7 @@ sg_test_rwbuf_LDADD = ../lib/libsgutils2.la
sg_timestamp_LDADD = ../lib/libsgutils2.la
-sg_turs_LDADD = ../lib/libsgutils2.la
+sg_turs_LDADD = ../lib/libsgutils2.la @RT_LIB@
sg_unmap_LDADD = ../lib/libsgutils2.la
diff --git a/src/Makefile.in b/src/Makefile.in
index 59d11661..b4f07c0f 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -644,7 +644,7 @@ sg_stream_ctl_LDADD = ../lib/libsgutils2.la
sg_sync_LDADD = ../lib/libsgutils2.la
sg_test_rwbuf_LDADD = ../lib/libsgutils2.la
sg_timestamp_LDADD = ../lib/libsgutils2.la
-sg_turs_LDADD = ../lib/libsgutils2.la
+sg_turs_LDADD = ../lib/libsgutils2.la @RT_LIB@
sg_unmap_LDADD = ../lib/libsgutils2.la
sg_verify_LDADD = ../lib/libsgutils2.la
sg_vpd_SOURCES = sg_vpd.c sg_vpd_vendor.c
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index f73806ed..45a6e176 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -40,7 +40,7 @@
*/
-static const char * version_str = "1.51 20190202"; /* spc5r20 + sbc4r15 */
+static const char * version_str = "1.52 20190210"; /* spc5r20 + sbc4r15 */
/* standard VPD pages, in ascending page number order */
#define VPD_SUPPORTED_VPDS 0x0
@@ -292,8 +292,8 @@ usage()
" --version|-V print version string and exit\n\n"
"Fetch Vital Product Data (VPD) page using SCSI INQUIRY or "
"decodes VPD\npage response held in file FN. To list available "
- "pages use '-e'. Also\n'-p -1' yields the standard INQUIRY "
- "response.\n");
+ "pages use '-e'. Also\n'-p -1' or '-p sinq' yields the standard "
+ "INQUIRY response.\n");
}
/* Read ASCII hex bytes or binary from fname (a file named '-' taken as
diff --git a/testing/sg_tst_nvme.c b/testing/sg_tst_nvme.c
index 6ec9734e..08bd0314 100644
--- a/testing/sg_tst_nvme.c
+++ b/testing/sg_tst_nvme.c
@@ -8,7 +8,7 @@
*
* This program issues a NVMe Identify command (controller or namespace)
* or a Device self-test command via the "SCSI" pass-through interface of
- * this packages sg_utils library. That interface is primarily shown in
+ * this package's sg_utils library. That interface is primarily shown in
* the ../include/sg_pt.h header file.
*
*/
diff --git a/testing/sgh_dd.c b/testing/sgh_dd.c
index a5641ed6..adcf7818 100644
--- a/testing/sgh_dd.c
+++ b/testing/sgh_dd.c
@@ -98,7 +98,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "1.18 20190204";
+static const char * version_str = "1.19 20190210";
#ifdef __GNUC__
#ifndef __clang__
@@ -168,7 +168,7 @@ typedef struct global_collection
int help;
int elem_sz;
struct flags_t in_flags;
- int64_t in_blk; /* -\ next block address to read */
+ // int64_t in_blk; /* -\ next block address to read */
int64_t in_count; /* | blocks remaining for next read */
int64_t in_rem_count; /* | count of remaining in blocks */
int in_partial; /* | */
@@ -216,7 +216,8 @@ typedef struct request_element
int outfd;
int out2fd;
int outregfd;
- int64_t blk;
+ int64_t iblk;
+ int64_t oblk;
int num_blks;
uint8_t * buffp;
uint8_t * alloc_bp;
@@ -246,6 +247,7 @@ typedef struct thread_info
} Thread_info;
static atomic_int mono_pack_id = 0;
+static atomic_long pos_index = 0;
static sigset_t signal_set;
static pthread_t sig_listen_thread_id;
@@ -801,7 +803,7 @@ read_write_thread(void * v_tip)
Rq_elem * rep = &rel;
int sz, blocks, status, vb, err, res;
int num_sg = 0;
- int64_t seek_skip;
+ int64_t my_index;
volatile bool stop_after_write = false;
bool own_infd = false;
bool own_outfd = false;
@@ -812,7 +814,6 @@ read_write_thread(void * v_tip)
clp = tip->gcp;
vb = clp->debug;
sz = clp->bpt * clp->bs;
- seek_skip = clp->seek - clp->skip;
memset(rep, 0, sizeof(Rq_elem));
/* Following clp members are constant during lifetime of thread */
rep->id = tip->id;
@@ -916,6 +917,7 @@ read_write_thread(void * v_tip)
/* vvvvvvvvvvvvvv Main segment copy loop vvvvvvvvvvvvvvvvvvvvvvv */
while (1) {
rep->wr = false;
+ my_index = atomic_fetch_add(&pos_index, clp->bpt);
/* Start of READ half of a segment */
status = pthread_mutex_lock(&clp->in_mutex);
if (0 != status) err_exit(status, "lock in_mutex");
@@ -925,10 +927,23 @@ read_write_thread(void * v_tip)
if (0 != status) err_exit(status, "unlock in_mutex");
break;
}
- blocks = (clp->in_count > clp->bpt) ? clp->bpt : clp->in_count;
- rep->blk = clp->in_blk;
+ if (dd_count >= 0) {
+ if (my_index >= dd_count) {
+ status = pthread_mutex_unlock(&clp->in_mutex);
+ if (0 != status) err_exit(status, "unlock in_mutex");
+ break;
+ } else if ((my_index + clp->bpt) > dd_count)
+ blocks = dd_count - my_index;
+ else
+ blocks = clp->bpt;
+ } else
+ blocks = clp->bpt;
+
+ rep->iblk = clp->skip + my_index;
+ rep->oblk = clp->seek + my_index;
rep->num_blks = blocks;
- clp->in_blk += blocks;
+
+ // clp->in_blk += blocks;
clp->in_count -= blocks;
pthread_cleanup_push(cleanup_in, (void *)clp);
@@ -956,7 +971,7 @@ read_write_thread(void * v_tip)
goto skip_force_out_sequence;
if (share_and_ofreg || (FT_DEV_NULL != clp->out_type)) {
while ((! clp->out_stop) &&
- ((rep->blk + seek_skip) != clp->out_blk)) {
+ (rep->oblk != clp->out_blk)) {
/* if write would be out of sequence then wait */
pthread_cleanup_push(cleanup_out, (void *)clp);
status = pthread_cond_wait(&clp->out_sync_cv, &clp->out_mutex);
@@ -975,7 +990,7 @@ skip_force_out_sequence:
}
if (stop_after_write)
clp->out_stop = true;
- rep->blk = clp->out_blk;
+
clp->out_blk += blocks;
clp->out_count -= blocks;
@@ -1001,7 +1016,7 @@ skip_force_out_sequence:
}
/* Output to OFILE */
if (FT_SG == clp->out_type) {
- if (rep->swait) {
+ if (rep->swait) { /* done already in sg_in_out_interleave() */
status = pthread_mutex_unlock(&clp->out_mutex);
if (0 != status) err_exit(status, "unlock out_mutex");
} else
@@ -1068,9 +1083,21 @@ static bool
normal_in_rd(Gbl_coll * clp, Rq_elem * rep, int blocks)
{
bool stop_after_write = false;
+ bool same_fds = rep->in_flags.same_fds || rep->out_flags.same_fds;
int res;
char strerr_buff[STRERR_BUFF_LEN];
+ if (! same_fds) { /* each has own file pointer, so we need to move it */
+ int64_t pos = rep->iblk * clp->bs;
+
+ if (lseek64(rep->infd, pos, SEEK_SET) < 0) { /* problem if pipe! */
+ pr2serr_lk("%s: tid=%d: >> lseek64(%" PRId64 "): %s\n", __func__,
+ rep->id, pos, safe_strerror(errno));
+ clp->in_stop = true;
+ guarded_stop_out(clp);
+ return true;
+ }
+ }
/* enters holding in_mutex */
while (((res = read(clp->infd, rep->buffp, blocks * clp->bs)) < 0) &&
((EINTR == errno) || (EAGAIN == errno)))
@@ -1079,7 +1106,7 @@ normal_in_rd(Gbl_coll * clp, Rq_elem * rep, int blocks)
if (clp->in_flags.coe) {
memset(rep->buffp, 0, rep->num_blks * rep->bs);
pr2serr_lk("tid=%d: >> substituted zeros for in blk=%" PRId64
- " for %d bytes, %s\n", rep->id, rep->blk,
+ " for %d bytes, %s\n", rep->id, rep->iblk,
rep->num_blks * rep->bs,
tsafe_strerror(errno, strerr_buff));
res = rep->num_blks * clp->bs;
@@ -1089,7 +1116,7 @@ normal_in_rd(Gbl_coll * clp, Rq_elem * rep, int blocks)
tsafe_strerror(errno, strerr_buff));
clp->in_stop = true;
guarded_stop_out(clp);
- return 1;
+ return true;
}
}
if (res < blocks * clp->bs) {
@@ -1101,10 +1128,10 @@ normal_in_rd(Gbl_coll * clp, Rq_elem * rep, int blocks)
clp->in_partial++;
}
/* Reverse out + re-apply blocks on clp */
- clp->in_blk -= o_blocks;
+ // clp->in_blk -= o_blocks;
clp->in_count += o_blocks;
rep->num_blks = blocks;
- clp->in_blk += blocks;
+ // clp->in_blk += blocks;
clp->in_count -= blocks;
}
clp->in_rem_count -= blocks;
@@ -1124,7 +1151,7 @@ normal_out_wr(Gbl_coll * clp, Rq_elem * rep, int blocks)
if (res < 0) {
if (clp->out_flags.coe) {
pr2serr_lk("tid=%d: >> ignored error for out blk=%" PRId64
- " for %d bytes, %s\n", rep->id, rep->blk,
+ " for %d bytes, %s\n", rep->id, rep->oblk,
rep->num_blks * rep->bs,
tsafe_strerror(errno, strerr_buff));
res = rep->num_blks * clp->bs;
@@ -1231,7 +1258,7 @@ sg_in_rd_cmd(Gbl_coll * clp, Rq_elem * rep)
err_exit(ENOMEM, "sg starting in command");
else if (res < 0) {
pr2serr_lk("tid=%d: inputting to sg failed, blk=%" PRId64 "\n",
- rep->id, rep->blk);
+ rep->id, rep->iblk);
status = pthread_mutex_unlock(&clp->in_mutex);
if (0 != status) err_exit(status, "unlock in_mutex");
guarded_stop_both(clp);
@@ -1261,7 +1288,7 @@ sg_in_rd_cmd(Gbl_coll * clp, Rq_elem * rep)
} else {
memset(rep->buffp, 0, rep->num_blks * rep->bs);
pr2serr_lk("tid=%d: >> substituted zeros for in blk=%" PRId64
- " for %d bytes\n", rep->id, rep->blk,
+ " for %d bytes\n", rep->id, rep->iblk,
rep->num_blks * rep->bs);
}
#if defined(__GNUC__)
@@ -1355,7 +1382,7 @@ sg_out_wr_cmd(Gbl_coll * clp, Rq_elem * rep, bool is_wr2)
err_exit(ENOMEM, "sg starting out command");
else if (res < 0) {
pr2serr_lk("%soutputting from sg failed, blk=%" PRId64 "\n",
- my_name, rep->blk);
+ my_name, rep->oblk);
status = pthread_mutex_unlock(mutexp);
if (0 != status) err_exit(status, "unlock out_mutex");
guarded_stop_both(clp);
@@ -1384,7 +1411,7 @@ sg_out_wr_cmd(Gbl_coll * clp, Rq_elem * rep, bool is_wr2)
goto fini;
} else
pr2serr_lk(">> ignored error for out blk=%" PRId64 " for %d "
- "bytes\n", rep->blk, rep->num_blks * rep->bs);
+ "bytes\n", rep->oblk, rep->num_blks * rep->bs);
#if defined(__GNUC__)
#if (__GNUC__ >= 7)
__attribute__((fallthrough));
@@ -1431,6 +1458,7 @@ sg_start_io(Rq_elem * rep, bool is_wr2)
int cdbsz = wr ? rep->cdbsz_out : rep->cdbsz_in;
int flags = 0;
int res, err, fd;
+ int64_t blk = wr ? rep->oblk : rep->iblk;
struct sg_io_hdr * hp = &rep->io_hdr;
struct sg_io_v4 * h4p = &rep->io_hdr4;
const char * cp = "";
@@ -1445,10 +1473,10 @@ sg_start_io(Rq_elem * rep, bool is_wr2)
fd = rep->infd;
crwp = "reading";
}
- if (sg_build_scsi_cdb(rep->cmd, cdbsz, rep->num_blks, rep->blk,
- wr, fua, dpo)) {
+ if (sg_build_scsi_cdb(rep->cmd, cdbsz, rep->num_blks, blk, wr, fua,
+ dpo)) {
pr2serr_lk("%sbad cdb build, start_blk=%" PRId64 ", blocks=%d\n",
- my_name, rep->blk, rep->num_blks);
+ my_name, blk, rep->num_blks);
return -1;
}
if (mmap && (rep->outregfd >= 0)) {
@@ -1475,7 +1503,7 @@ sg_start_io(Rq_elem * rep, bool is_wr2)
if (rep->debug > 3) {
pr2serr_lk("%s tid,rq_id=%d,%d: SCSI %s%s%s%s, blk=%" PRId64
" num_blks=%d\n", __func__, rep->id, rep->rq_id, crwp, cp,
- c2p, c3p, rep->blk, rep->num_blks);
+ c2p, c3p, blk, rep->num_blks);
lk_print_command(rep->cmd);
}
if (v4)
@@ -1569,6 +1597,7 @@ sg_finish_io(bool wr, Rq_elem * rep, bool is_wr2)
{
bool v4 = wr ? rep->out_flags.v4 : rep->in_flags.v4;
int res, fd;
+ int64_t blk = wr ? rep->oblk : rep->iblk;
struct sg_io_hdr io_hdr;
struct sg_io_hdr * hp;
struct sg_io_v4 * h4p;
@@ -1621,7 +1650,7 @@ sg_finish_io(bool wr, Rq_elem * rep, bool is_wr2)
{
char ebuff[EBUFF_SZ];
- snprintf(ebuff, EBUFF_SZ, "%s blk=%" PRId64, cp, rep->blk);
+ snprintf(ebuff, EBUFF_SZ, "%s blk=%" PRId64, cp, blk);
lk_chk_n_print3(ebuff, hp, false);
return res;
}
@@ -1671,7 +1700,7 @@ do_v4:
char ebuff[EBUFF_SZ];
snprintf(ebuff, EBUFF_SZ, "%s rq_id=%d, blk=%" PRId64, cp,
- rep->rq_id, rep->blk);
+ rep->rq_id, blk);
lk_chk_n_print4(ebuff, h4p, false);
if ((rep->debug > 4) && h4p->info)
pr2serr_lk(" info=0x%x sg_info_check=%d another_waiting=%d "
@@ -1723,7 +1752,7 @@ sg_in_out_interleave(Gbl_coll *clp, Rq_elem * rep)
err_exit(ENOMEM, "sg interleave starting in command");
else if (res < 0) {
pr2serr_lk("tid=%d: inputting to sg failed, blk=%" PRId64 "\n",
- rep->id, rep->blk);
+ rep->id, rep->iblk);
status = pthread_mutex_unlock(&clp->in_mutex);
if (0 != status) err_exit(status, "unlock in_mutex");
guarded_stop_both(clp);
@@ -1732,14 +1761,13 @@ sg_in_out_interleave(Gbl_coll *clp, Rq_elem * rep)
/* start WRITE */
rep->wr = true;
- rep->blk = clp->out_blk;
res = sg_start_io(rep, false);
pid_write = rep->rq_id;
if (1 == res)
err_exit(ENOMEM, "sg interleave starting out command");
else if (res < 0) {
pr2serr_lk("tid=%d: outputting to sg failed, blk=%" PRId64 "\n",
- rep->id, rep->blk);
+ rep->id, rep->oblk);
status = pthread_mutex_unlock(&clp->in_mutex);
if (0 != status) err_exit(status, "unlock in_mutex");
guarded_stop_both(clp);
@@ -1752,7 +1780,6 @@ sg_in_out_interleave(Gbl_coll *clp, Rq_elem * rep)
/* finish READ */
rep->rq_id = pid_read;
rep->wr = false;
- rep->blk = clp->in_blk;
res = sg_finish_io(rep->wr, rep, false);
switch (res) {
case SG_LIB_CAT_ABORTED_COMMAND:
@@ -1774,7 +1801,7 @@ sg_in_out_interleave(Gbl_coll *clp, Rq_elem * rep)
} else {
memset(rep->buffp, 0, rep->num_blks * rep->bs);
pr2serr_lk("tid=%d: >> substituted zeros for in blk=%" PRId64
- " for %d bytes\n", rep->id, rep->blk,
+ " for %d bytes\n", rep->id, rep->iblk,
rep->num_blks * rep->bs);
}
#if defined(__GNUC__)
@@ -1808,7 +1835,6 @@ sg_in_out_interleave(Gbl_coll *clp, Rq_elem * rep)
/* finish WRITE, no lock held */
rep->rq_id = pid_write;
rep->wr = true;
- rep->blk = clp->out_blk;
res = sg_finish_io(rep->wr, rep, false);
switch (res) {
case SG_LIB_CAT_ABORTED_COMMAND:
@@ -1828,7 +1854,7 @@ sg_in_out_interleave(Gbl_coll *clp, Rq_elem * rep)
return;
} else
pr2serr_lk(">> ignored error for out blk=%" PRId64 " for %d "
- "bytes\n", rep->blk, rep->num_blks * rep->bs);
+ "bytes\n", rep->oblk, rep->num_blks * rep->bs);
#if defined(__GNUC__)
#if (__GNUC__ >= 7)
__attribute__((fallthrough));
@@ -2687,7 +2713,7 @@ main(int argc, char * argv[])
clp->in_count = dd_count;
clp->in_rem_count = dd_count;
clp->skip = skip;
- clp->in_blk = skip;
+ // clp->in_blk = skip;
clp->out_count = dd_count;
clp->out_rem_count = dd_count;
clp->seek = seek;
diff --git a/utils/hxascdmp.1 b/utils/hxascdmp.1
index 16300aa3..22814922 100644
--- a/utils/hxascdmp.1
+++ b/utils/hxascdmp.1
@@ -1,10 +1,10 @@
-.TH HXASCDMP "1" "February 2014" "sg3_utils\-1.38" SG3_UTILS
+.TH HXASCDMP "1" "February 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
hxascdmp \- hexadecimal ASCII dump
.SH SYNOPSIS
.B hxascdmp
-[\fI\-b=BPL\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-N\fR] [\fI\-V\fR]
-[\fIFILE+\fR]
+[\fI\-b=BPL\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-N\fR] [\fI\-o=OFF\fR]
+[\fI\-V\fR] [\fIFILE+\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -46,6 +46,11 @@ end of each line).
\fB\-N\fR
no address; so each line starts with the next hexadecimal byte.
.TP
+\fB\-o\fR=\fIOFF\fR
+where \fIOFF\fR specifies the byte offset from the beginning of the pipe or
+the beginning of each file that the output starts. If the address is being
+printed out then it starts at \fIOFF\fR. The default is an \fIOFF\fR of 0 .
+.TP
\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
.SH NOTES
@@ -98,7 +103,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004\-2014 Douglas Gilbert
+Copyright \(co 2004\-2019 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/utils/hxascdmp.c b/utils/hxascdmp.c
index 9f6566d3..4184c037 100644
--- a/utils/hxascdmp.c
+++ b/utils/hxascdmp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2014 Douglas Gilbert.
+ * Copyright (c) 2004-2019 Douglas Gilbert.
* All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the BSD_LICENSE file.
@@ -14,12 +14,16 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#define DEF_BYTES_PER_LINE 16
static int bytes_per_line = DEF_BYTES_PER_LINE;
-static const char * version_str = "1.15 20181207";
+static const char * version_str = "1.17 20190210";
#define CHARS_PER_HEX_BYTE 3
#define BINARY_START_COL 6
@@ -73,6 +77,126 @@ num_chs_in_str(const char * s, int slen, int ch)
return res;
}
+/* If the number in 'buf' can be decoded or the multiplier is unknown
+ * then -1LL is returned. Accepts a hex prefix (0x or 0X) or a decimal
+ * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
+ * Main (SI) multipliers supported: K, M, G, T, P. Ignore leading spaces
+ * and tabs; accept comma, hyphen, space, tab and hash as terminator. */
+int64_t
+sg_get_llnum(const char * buf)
+{
+ int res, len, n;
+ int64_t num, ll;
+ uint64_t unum;
+ char * cp;
+ const char * b;
+ char c = 'c';
+ char c2 = '\0'; /* keep static checker happy */
+ char c3 = '\0'; /* keep static checker happy */
+ char lb[32];
+
+ if ((NULL == buf) || ('\0' == buf[0]))
+ return -1LL;
+ len = strlen(buf);
+ n = strspn(buf, " \t");
+ if (n > 0) {
+ if (n == len)
+ return -1LL;
+ buf += n;
+ len -= n;
+ }
+ /* following hack to keep C++ happy */
+ cp = strpbrk((char *)buf, " \t,#-");
+ if (cp) {
+ len = cp - buf;
+ n = (int)sizeof(lb) - 1;
+ len = (len < n) ? len : n;
+ memcpy(lb, buf, len);
+ lb[len] = '\0';
+ b = lb;
+ } else
+ b = buf;
+ if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) {
+ res = sscanf(b + 2, "%" SCNx64 , &unum);
+ num = unum;
+ } else if ('H' == toupper((int)b[len - 1])) {
+ res = sscanf(b, "%" SCNx64 , &unum);
+ num = unum;
+ } else
+ res = sscanf(b, "%" SCNd64 "%c%c%c", &num, &c, &c2, &c3);
+ if (res < 1)
+ return -1LL;
+ else if (1 == res)
+ return num;
+ else {
+ if (res > 2)
+ c2 = toupper((int)c2);
+ if (res > 3)
+ c3 = toupper((int)c3);
+ switch (toupper((int)c)) {
+ case 'C':
+ return num;
+ case 'W':
+ return num * 2;
+ case 'B':
+ return num * 512;
+ case 'K':
+ if (2 == res)
+ return num * 1024;
+ if (('B' == c2) || ('D' == c2))
+ return num * 1000;
+ if (('I' == c2) && (4 == res) && ('B' == c3))
+ return num * 1024;
+ return -1LL;
+ case 'M':
+ if (2 == res)
+ return num * 1048576;
+ if (('B' == c2) || ('D' == c2))
+ return num * 1000000;
+ if (('I' == c2) && (4 == res) && ('B' == c3))
+ return num * 1048576;
+ return -1LL;
+ case 'G':
+ if (2 == res)
+ return num * 1073741824;
+ if (('B' == c2) || ('D' == c2))
+ return num * 1000000000;
+ if (('I' == c2) && (4 == res) && ('B' == c3))
+ return num * 1073741824;
+ return -1LL;
+ case 'T':
+ if (2 == res)
+ return num * 1099511627776LL;
+ if (('B' == c2) || ('D' == c2))
+ return num * 1000000000000LL;
+ if (('I' == c2) && (4 == res) && ('B' == c3))
+ return num * 1099511627776LL;
+ return -1LL;
+ case 'P':
+ if (2 == res)
+ return num * 1099511627776LL * 1024;
+ if (('B' == c2) || ('D' == c2))
+ return num * 1000000000000LL * 1000;
+ if (('I' == c2) && (4 == res) && ('B' == c3))
+ return num * 1099511627776LL * 1024;
+ return -1LL;
+ case 'X':
+ cp = (char *)strchr(b, 'x');
+ if (NULL == cp)
+ cp = (char *)strchr(b, 'X');
+ if (cp) {
+ ll = sg_get_llnum(cp + 1);
+ if (-1LL != ll)
+ return num * ll;
+ }
+ return -1LL;
+ default:
+ fprintf(stderr, "unrecognized multiplier\n");
+ return -1LL;
+ }
+ }
+}
+
static void
dStrHex(const char* str, int len, long start, int noAddr)
{
@@ -202,6 +326,8 @@ usage()
fprintf(stderr, " -H print hex only (i.e. no ASCII "
"to right)\n");
fprintf(stderr, " -N no address, start in first column\n");
+ fprintf(stderr, " -o=<off> start decoding at byte <off>. Suffix "
+ "multipliers allowed\n");
fprintf(stderr, " -V print version string then exits\n");
fprintf(stderr, " -? print this usage message\n");
fprintf(stderr, " <file>+ reads file(s) and outputs each "
@@ -216,6 +342,7 @@ main(int argc, const char ** argv)
char buff[8192];
int num = 8192;
long start = 0;
+ int64_t offset = 0;
int res, k, u, len, n;
int inFile = STDIN_FILENO;
int doHelp = 0;
@@ -237,6 +364,15 @@ main(int argc, const char ** argv)
return 1;
}
bytes_per_line = u;
+ } else if (0 == strncmp("-o=", cp, 3)) {
+ int64_t off = sg_get_llnum(cp + 3);
+
+ if (off == -1) {
+ fprintf(stderr, "Bad value after '-o=' option\n");
+ usage();
+ return 1;
+ }
+ offset = off;
} else if ((len > 1) && ('-' == cp[0]) && ('-' != cp[1])) {
res = 0;
n = num_chs_in_str(cp + 1, len - 1, 'h');
@@ -292,7 +428,21 @@ main(int argc, const char ** argv)
ret = 1;
} else {
sg_set_binary_mode(inFile);
- start = 0;
+ if (offset > 0) {
+ int err;
+ int64_t off_res;
+
+ off_res = lseek(inFile, offset, SEEK_SET);
+ if (off_res < 0) {
+ err = errno;
+ fprintf(stderr, "failed moving filepos: wanted=%"
+ PRId64 " [0x%" PRIx64 "]\nlseek error: %s\n",
+ offset, offset, strerror(err));
+ goto fini1;
+ }
+ start = offset;
+ } else
+ start = 0;
if (! doHex)
printf("ASCII hex dump of file: %s\n", argv[k]);
while ((res = read(inFile, buff, num)) > 0) {
@@ -303,10 +453,24 @@ main(int argc, const char ** argv)
start += (long)res;
}
}
+fini1:
close(inFile);
}
} else {
sg_set_binary_mode(inFile);
+ if (offset > 0) {
+ start = offset;
+ do { /* eat up offset bytes */
+ if ((res = read(inFile, buff,
+ (num > offset ? offset : num))) > 0)
+ offset -= res;
+ else {
+ fprintf(stderr, "offset read() error: %s\n",
+ strerror(errno));
+ break;
+ }
+ } while (offset > 0);
+ }
while ((res = read(inFile, buff, num)) > 0) {
if (doHex)
dStrHexOnly(buff, res, start, noAddr);