aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2022-06-27 18:26:54 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2022-06-27 18:26:54 +0000
commit30842a3103045e471ec8169f09135bb6766e5e1d (patch)
treea37d6d0bc773726fff04c163457d3bb22e6efa71
parent2e225c87784735360e9619766efe06782179a86a (diff)
downloadsg3_utils-30842a3103045e471ec8169f09135bb6766e5e1d.tar.gz
more JSON work: sense data and vpd device id, start on sg_vpd
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@956 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog2
-rw-r--r--include/sg_pr2serr.h11
-rw-r--r--inhex/descriptor_sense.hex30
-rw-r--r--inhex/vpd_di_all.hex30
-rw-r--r--lib/sg_lib.c24
-rw-r--r--lib/sg_pr2serr.c424
-rwxr-xr-xscripts/rescan-scsi-bus.sh2
-rw-r--r--src/sg_decode_sense.c39
-rw-r--r--src/sg_get_elem_status.c14
-rw-r--r--src/sg_get_lba_status.c16
-rw-r--r--src/sg_opcodes.c22
-rw-r--r--src/sg_rep_zones.c18
-rw-r--r--src/sg_vpd.c233
-rw-r--r--src/sg_vpd.h79
-rw-r--r--src/sg_vpd_vendor.c42
-rw-r--r--testing/Makefile2
-rw-r--r--testing/tst_sg_lib.c148
17 files changed, 739 insertions, 397 deletions
diff --git a/ChangeLog b/ChangeLog
index 75f8d6e9..722cd20f 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 pre-release sg3_utils-1.48 [20220625] [svn: r955]
+Changelog for pre-release sg3_utils-1.48 [20220627] [svn: r956]
- some utilities: add experimental --json[=JO] option
- sg_z_act_query: new utility for sending either a
Zone activate or Zone query command
diff --git a/include/sg_pr2serr.h b/include/sg_pr2serr.h
index 9a1fd273..1577b6ce 100644
--- a/include/sg_pr2serr.h
+++ b/include/sg_pr2serr.h
@@ -153,6 +153,9 @@ sgj_opaque_p sgj_new_named_array(sgj_state * jsp, sgj_opaque_p jop,
* a pointer newly formed JSON string. */
sgj_opaque_p sgj_add_nv_s(sgj_state * jsp, sgj_opaque_p jop,
const char * name, const char * value);
+sgj_opaque_p sgj_add_nv_s_len(sgj_state * jsp, sgj_opaque_p jop,
+ const char * name,
+ const char * value, int slen);
/* If either jsp is NULL or jsp->pr_as_json is false then nothing happens and
* NULL is returned. The insertion point is at jop but if it is NULL
@@ -256,6 +259,12 @@ void sgj_add_nv_ihexstr_ane(sgj_state * jsp, sgj_opaque_p jop,
const char * str_name, const char * val_s,
const char * ane_s);
+/* Breaks up the string pointed to by 'sp' into lines and adds them to the
+ * jsp->outputp array. Treat '\n' in sp as line breaks. Consumes characters
+ * from sp until either a '\0' is found or slen is exhausted. Add each line
+ * to jsp->outputp JSON array (if conditions met). */
+void sgj_pr_str_output(sgj_state * jsp, const char * sp, int slen);
+
/* This function only produces JSON output if jsp is non-NULL and
* jsp->pr_as_json is true. 'sbp' is assumed to point to sense data as
* defined by T10 with a length of 'sb_len' bytes. Returns false if an
@@ -287,6 +296,8 @@ void sgj_free_unattached(sgj_opaque_p jop);
* jsp->userp will all be set to NULL. */
void sgj_finish(sgj_state * jsp);
+char * sg_json_usage(int char_if_not_j, char * b, int blen);
+
#ifdef __cplusplus
}
diff --git a/inhex/descriptor_sense.hex b/inhex/descriptor_sense.hex
new file mode 100644
index 00000000..c0fcba97
--- /dev/null
+++ b/inhex/descriptor_sense.hex
@@ -0,0 +1,30 @@
+# Test descriptor format sense data. Values are in hex.
+# Invocation: 'sg_decode_sense -f descriptor_sense.hex' [dpg 20220626]
+
+
+# unrec_err, excessive_writes, sdat_ovfl, additional_len=?
+72 01 03 02 80 00 00 4c
+
+# Information: 0x11223344556677bb
+00 0a 80 00 11 22 33 44 55 66 77 bb
+
+# command specific: 0x3344556677bbccff
+01 0a 00 00 33 44 55 66 77 bb cc ff
+
+# sense key specific: SKSV=1, actual_count=257 (hex: 0x101)
+02 06 00 00 80 01 01 00
+
+# field replaceable code=0x45
+03 02 00 45
+
+# another progress report indicator
+0a 06 02 01 02 00 32 01
+
+# incorrect length indicator (ILI)
+05 02 00 20
+
+# user data segment referral
+0b 1a 01 00
+00 00 00 01 01 02 03 04 05 06 07 08
+01 02 03 04 55 06 07 08
+02 00 12 34
diff --git a/inhex/vpd_di_all.hex b/inhex/vpd_di_all.hex
index bc89c0b1..b0c93765 100644
--- a/inhex/vpd_di_all.hex
+++ b/inhex/vpd_di_all.hex
@@ -2,7 +2,7 @@
# An example invocation:
# sg_vpd --inhex=vpd_di_all.hex
-00 83 00 82
+00 83 01 04
# Vendor specific designator
01 00 00 16 11 22 33 44 55 66 77 88 99 aa bb cc
@@ -21,3 +21,31 @@ dd ee ff ed cb a9 87 65 43 21
# NAA
01 03 00 08 51 22 33 44 55 66 77 88
01 03 00 10 61 22 33 44 55 66 77 88 aa bb cc dd ee ff ee dd
+
+# Relative target port
+01 14 00 04 00 00 00 02
+
+# Target port group
+01 15 00 04 00 00 00 03
+
+# Logical unit group
+01 06 00 04 00 00 00 04
+
+# MD5 logical unitp
+01 07 00 10 ff ee dd cc bb aa 99 88 77 66 55 44 33 22 11 00
+
+# SCSI name string: iqn.5886.com.acme.diskarrays-sn-a8675309
+02 28 00 28
+69 71 6e 2e 35 38 38 36 2e 63 6f 6d 2e 61 63 6d
+65 2e 64 69 73 6b 61 72 72 61 79 73 2d 73 6e 2d
+61 38 36 37 35 33 30 39
+
+# Protocol specific
+# USB
+91 99 00 04 04 00 02 00
+# PCIe
+a1 99 00 08 01 23 00 00 00 00 00 00
+
+# UUID
+01 0a 00 12 10 00 11 22 33 44 55 66 77 88 99 aa
+bb cc dd ee fe dc
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index 418638b5..7256c435 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -2957,11 +2957,11 @@ dStrHexStr(const char * str, int len, const char * leadin, int oformat,
int b_len, char * b)
{
bool want_ascii = (0 == oformat);
- char lf_or = (oformat > 1) ? ' ' : '\n';
int bpstart, bpos, k, n, prior_ascii_len;
char buff[DSHS_LINE_BLEN + 2]; /* allow for trailing null */
char a[DSHS_BPL + 1]; /* printable ASCII bytes or '.' */
const char * p = str;
+ const char * lf_or = (oformat > 1) ? " " : "\n";
if (len <= 0) {
if (b_len > 0)
@@ -2974,16 +2974,20 @@ dStrHexStr(const char * str, int len, const char * leadin, int oformat,
memset(a, ' ', DSHS_BPL);
a[DSHS_BPL] = '\0';
}
+ n = 0;
+ bpstart = 0;
if (leadin) {
- bpstart = strlen(leadin);
- /* Cap leadin at (DSHS_LINE_BLEN - 70) characters */
- if (bpstart > (DSHS_LINE_BLEN - 70))
- bpstart = DSHS_LINE_BLEN - 70;
- } else
- bpstart = 0;
+ if (oformat > 1)
+ n += sg_scnpr(b + n, b_len - n, "%s", leadin);
+ else {
+ bpstart = strlen(leadin);
+ /* Cap leadin at (DSHS_LINE_BLEN - 70) characters */
+ if (bpstart > (DSHS_LINE_BLEN - 70))
+ bpstart = DSHS_LINE_BLEN - 70;
+ }
+ }
bpos = bpstart;
prior_ascii_len = bpstart + (DSHS_BPL * 3) + 1;
- n = 0;
memset(buff, ' ', DSHS_LINE_BLEN);
buff[DSHS_LINE_BLEN] = '\0';
if (bpstart > 0)
@@ -3005,7 +3009,7 @@ dStrHexStr(const char * str, int len, const char * leadin, int oformat,
prior_ascii_len, buff, a);
memset(a, ' ', DSHS_BPL);
} else
- n += sg_scnpr(b + n, b_len - n, "%s%c", buff, lf_or);
+ n += sg_scnpr(b + n, b_len - n, "%s%s", buff, lf_or);
if (n >= (b_len - 1))
goto fini;
memset(buff, ' ', DSHS_LINE_BLEN);
@@ -3021,7 +3025,7 @@ dStrHexStr(const char * str, int len, const char * leadin, int oformat,
n += sg_scnpr(b + n, b_len - n, "%-*s %s\n", prior_ascii_len,
buff, a);
else
- n += sg_scnpr(b + n, b_len - n, "%s%c", buff, lf_or);
+ n += sg_scnpr(b + n, b_len - n, "%s%s", buff, lf_or);
}
fini:
if (oformat > 1)
diff --git a/lib/sg_pr2serr.c b/lib/sg_pr2serr.c
index 9ae466b3..ccebaf86 100644
--- a/lib/sg_pr2serr.c
+++ b/lib/sg_pr2serr.c
@@ -63,21 +63,6 @@ pr2serr(const char * fmt, ...)
return n;
}
-/* local copy of snprntf() variant */
-static int
-scnpr(char * cp, int cp_max_len, const char * fmt, ...)
-{
- va_list args;
- int n;
-
- if (cp_max_len < 2)
- return 0;
- va_start(args, fmt);
- n = vsnprintf(cp, cp_max_len, fmt, args);
- va_end(args);
- return (n < cp_max_len) ? n : (cp_max_len - 1);
-}
-
static bool
sgj_parse_opts(sgj_state * jsp, const char * j_optarg)
{
@@ -149,6 +134,10 @@ sgj_parse_opts(sgj_state * jsp, const char * j_optarg)
case 'y':
jsp->pr_format = 'g';
break;
+ case '?':
+ bad_arg = true;
+ jsp->first_bad_char = '\0';
+ break;
default:
bad_arg = true;
if (0 == jsp->first_bad_char)
@@ -160,6 +149,77 @@ sgj_parse_opts(sgj_state * jsp, const char * j_optarg)
return ! bad_arg;
}
+char *
+sg_json_usage(int char_if_not_j, char * b, int blen)
+{
+ int n = 0;
+ char short_opt = char_if_not_j ? char_if_not_j : 'j';
+
+ if ((NULL == b) || (blen < 1))
+ goto fini;
+ n += sg_scnpr(b + n, blen - n, "JSON option usage:\n");
+ n += sg_scnpr(b + n, blen - n,
+ " --json[-JO] | -%c[JO]\n\n", short_opt);
+ n += sg_scnpr(b + n, blen - n, " where JO is a string of one or more "
+ "of:\n");
+ n += sg_scnpr(b + n, blen - n,
+ " 0 | 2 tab pretty output to 2 spaces\n");
+ n += sg_scnpr(b + n, blen - n,
+ " 4 tab pretty output to 4 spaces\n");
+ n += sg_scnpr(b + n, blen - n,
+ " 8 tab pretty output to 8 spaces\n");
+ if (n >= (blen - 1))
+ goto fini;
+ n += sg_scnpr(b + n, blen - n,
+ " a show 'abbreviated_name_expansion' "
+ "fields\n");
+ n += sg_scnpr(b + n, blen - n,
+ " e show 'exit_status' field\n");
+ n += sg_scnpr(b + n, blen - n,
+ " h show 'hex' fields\n");
+ n += sg_scnpr(b + n, blen - n,
+ " l show lead-in fields (invocation "
+ "information)\n");
+ n += sg_scnpr(b + n, blen - n,
+ " o non-JSON output placed in 'output' array in "
+ "lead-in\n");
+ if (n >= (blen - 1))
+ goto fini;
+ n += sg_scnpr(b + n, blen - n,
+ " p pretty print the JSON output\n");
+ n += sg_scnpr(b + n, blen - n,
+ " s show string output (usually fields named "
+ "'meaning')\n");
+ n += sg_scnpr(b + n, blen - n,
+ " v make JSON output more verbose\n");
+ n += sg_scnpr(b + n, blen - n,
+ " = ignored if first character, else it's an "
+ "error\n");
+ n += sg_scnpr(b + n, blen - n,
+ " - | ~ | ! toggle next letter setting\n");
+
+ n += sg_scnpr(b + n, blen - n, "\nIn the absence of the optional JO "
+ "argument, the following are set\non: 'elps' while the "
+ "others are set off, and tabs are set to 4.\nBefore "
+ "command line JO options are applied, the environment\n"
+ "variable: %s is applied (if present). Note that\nno "
+ "space is permitted between the short option ('-%c') "
+ "and its\nargument ('JO').\n", sgj_opts_ev, short_opt);
+fini:
+ return b;
+}
+
+char *
+sg_json_settings(sgj_state * jsp, char * b, int blen)
+{
+ snprintf(b, blen, "%d%sa%se%sh%sl%so%sp%ss%sv", jsp->pr_indent_size,
+ jsp->pr_ane ? "" : "-", jsp->pr_exit_status ? "" : "-",
+ jsp->pr_hex ? "" : "-", jsp->pr_leadin ? "" : "-",
+ jsp->pr_output ? "" : "-", jsp->pr_pretty ? "" : "-",
+ jsp->pr_string ? "" : "-", jsp->verbose ? "" : "-");
+ return b;
+}
+
static void
sgj_def_opts(sgj_state * jsp)
{
@@ -207,7 +267,6 @@ sgj_start(const char * util_name, const char * ver_str, int argc,
json_value * jv2p = NULL;
json_value * jap = NULL;
-
if (NULL == jvp)
return NULL;
if (NULL == jsp)
@@ -241,6 +300,18 @@ sgj_start(const char * util_name, const char * ver_str, int argc,
json_string_new("0.0"));
json_object_push((json_value *)jv2p, "argv", jap);
}
+ if (jsp->verbose) {
+ const char * cp = getenv(sgj_opts_ev);
+ char b[32];
+
+ json_object_push((json_value *)jv2p, "environment_variable_name",
+ json_string_new(sgj_opts_ev));
+ json_object_push((json_value *)jv2p, "environment_variable_value",
+ json_string_new(cp ? cp : "no available"));
+ sg_json_settings(jsp, b, sizeof(b));
+ json_object_push((json_value *)jv2p, "json_options",
+ json_string_new(b));
+ }
} else {
if (jsp->pr_output && util_name)
jv2p = json_object_push((json_value *)jvp, "utility_invoked",
@@ -264,9 +335,16 @@ sgj_pr2file(sgj_state * jsp, sgj_opaque_p jop, int exit_status, FILE * fp)
fprintf(fp, "%s: all NULL pointers ??\n", __func__);
return;
}
- if ((NULL == jop) && jsp->pr_exit_status)
- json_object_push(jvp, "exit_status", json_integer_new(exit_status));
+ if ((NULL == jop) && jsp->pr_exit_status) {
+ char d[80];
+ if (sg_exit2str(exit_status, jsp->verbose, sizeof(d), d)) {
+ if (0 == strlen(d))
+ strncpy(d, "no errors", sizeof(d) - 1);
+ } else
+ strncpy(d, "not available", sizeof(d) - 1);
+ sgj_add_nv_istr(jsp, jop, "exit_status", exit_status, NULL, d);
+ }
memcpy(&out_settings, &def_out_settings, sizeof(out_settings));
if (jsp->pr_indent_size != def_out_settings.indent_size)
out_settings.indent_size = jsp->pr_indent_size;
@@ -399,6 +477,22 @@ sgj_add_nv_s(sgj_state * jsp, sgj_opaque_p jop, const char * name,
}
sgj_opaque_p
+sgj_add_nv_s_len(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ const char * value, int slen)
+{
+ if (jsp && jsp->pr_as_json && value && (slen >= 0)) {
+ if (name)
+ return json_object_push((json_value *)(jop ? jop : jsp->basep),
+ name, json_string_new_length(slen,
+ value));
+ else
+ return json_array_push((json_value *)(jop ? jop : jsp->basep),
+ json_string_new_length(slen, value));
+ } else
+ return NULL;
+}
+
+sgj_opaque_p
sgj_add_nv_i(sgj_state * jsp, sgj_opaque_p jop, const char * name,
int64_t value)
{
@@ -549,6 +643,7 @@ sgj_add_nv_ihex_ane(sgj_state * jsp, sgj_opaque_p jop, const char * name,
}
}
+/* Add hex byte strings irrespective of jsp->pr_hex setting. */
void
sgj_add_nv_hex_bytes(sgj_state * jsp, sgj_opaque_p jop, const char * name,
const uint8_t * byte_arr, int num_bytes)
@@ -556,7 +651,7 @@ sgj_add_nv_hex_bytes(sgj_state * jsp, sgj_opaque_p jop, const char * name,
int blen = num_bytes * 4;
char * bp;
- if ((NULL == jsp) || (! jsp->pr_as_json) || (! jsp->pr_hex))
+ if ((NULL == jsp) || (! jsp->pr_as_json))
return;
bp = (char *)calloc(blen + 4, 1);
if (bp) {
@@ -607,6 +702,37 @@ sgj_add_nv_ihexstr_ane(sgj_state * jsp, sgj_opaque_p jop, const char * name,
}
}
+/* Treat '\n' in sp as line breaks. Consumes characters from sp until either
+ * a '\0' is found or slen is exhausted. Add each line to jsp->outputp JSON
+ * array (if conditions met). */
+void
+sgj_pr_str_output(sgj_state * jsp, const char * sp, int slen)
+{
+ char c;
+ int k, n;
+ const char * prev_sp = sp;
+ const char * cur_sp = sp;
+
+ if ((NULL == jsp) || (NULL == jsp->outputp) || (! jsp->pr_as_json) ||
+ (! jsp->pr_output))
+ return;
+ for (k = 0; k < slen; ++k, ++cur_sp) {
+ c = *cur_sp;
+ if ('\0' == c)
+ break;
+ else if ('\n' == c) {
+ n = cur_sp - prev_sp;
+ /* when name is NULL, add to array (jsp->outputp) */
+ sgj_add_nv_s_len(jsp, jsp->outputp, NULL, prev_sp, n);
+ prev_sp = cur_sp + 1;
+ }
+ }
+ if (prev_sp < cur_sp) {
+ n = cur_sp - prev_sp;
+ sgj_add_nv_s_len(jsp, jsp->outputp, NULL, prev_sp, n);
+ }
+}
+
/* Returns number of characters placed in 'out' excluding trailing NULL */
static int
sgj_jsonify_name(const char * in, char * out, int maxlen_out)
@@ -667,14 +793,14 @@ sgj_pr_hr_js_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
if ((! as_json) || (jsp && jsp->pr_output)) {
switch (jtype) {
case json_string:
- scnpr(b + n, blen - n, "%s", jvp->u.string.ptr);
+ sg_scnpr(b + n, blen - n, "%s", jvp->u.string.ptr);
break;
case json_integer:
- scnpr(b + n, blen - n, "%" PRIi64, jvp->u.integer);
+ sg_scnpr(b + n, blen - n, "%" PRIi64, jvp->u.integer);
break;
case json_boolean:
- scnpr(b + n, blen - n, "%s",
- jvp->u.boolean ? "true" : "false");
+ sg_scnpr(b + n, blen - n, "%s",
+ jvp->u.boolean ? "true" : "false");
break;
case json_none:
default:
@@ -699,7 +825,7 @@ sgj_pr_hr_js_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
json_builder_free((json_value *)jvp);
return;
}
- n += scnpr(b + n, blen - n, "%s", name);
+ n += sg_scnpr(b + n, blen - n, "%s", name);
if (as_json) {
int k;
@@ -717,41 +843,41 @@ sgj_pr_hr_js_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
case SGJ_SEP_NONE:
break;
case SGJ_SEP_SPACE_1:
- n += scnpr(b + n, blen - n, " ");
+ n += sg_scnpr(b + n, blen - n, " ");
break;
case SGJ_SEP_SPACE_2:
- n += scnpr(b + n, blen - n, " ");
+ n += sg_scnpr(b + n, blen - n, " ");
break;
case SGJ_SEP_SPACE_3:
- n += scnpr(b + n, blen - n, " ");
+ n += sg_scnpr(b + n, blen - n, " ");
break;
case SGJ_SEP_SPACE_4:
- n += scnpr(b + n, blen - n, " ");
+ n += sg_scnpr(b + n, blen - n, " ");
break;
case SGJ_SEP_EQUAL_NO_SPACE:
- n += scnpr(b + n, blen - n, "=");
+ n += sg_scnpr(b + n, blen - n, "=");
break;
case SGJ_SEP_EQUAL_1_SPACE:
- n += scnpr(b + n, blen - n, "= ");
+ n += sg_scnpr(b + n, blen - n, "= ");
break;
case SGJ_SEP_COLON_NO_SPACE:
- n += scnpr(b + n, blen - n, ":");
+ n += sg_scnpr(b + n, blen - n, ":");
break;
case SGJ_SEP_COLON_1_SPACE:
- n += scnpr(b + n, blen - n, ": ");
+ n += sg_scnpr(b + n, blen - n, ": ");
break;
default:
break;
}
switch (jtype) {
case json_string:
- scnpr(b + n, blen - n, "%s", jvp->u.string.ptr);
+ sg_scnpr(b + n, blen - n, "%s", jvp->u.string.ptr);
break;
case json_integer:
- scnpr(b + n, blen - n, "%" PRIi64, jvp->u.integer);
+ sg_scnpr(b + n, blen - n, "%" PRIi64, jvp->u.integer);
break;
case json_boolean:
- scnpr(b + n, blen - n, "%s", jvp->u.boolean ? "true" : "false");
+ sg_scnpr(b + n, blen - n, "%s", jvp->u.boolean ? "true" : "false");
break;
case json_none:
default:
@@ -818,6 +944,7 @@ sgj_get_designation_descriptor(sgj_state * jsp, sgj_opaque_p jop,
char b[256];
const char * cp;
const char * naa_sp;
+ sgj_opaque_p jo2p;
static const int blen = sizeof(b);
static const int elen = sizeof(e);
@@ -858,7 +985,7 @@ sgj_get_designation_descriptor(sgj_state * jsp, sgj_opaque_p jop,
sgj_add_nv_ihexstr(jsp, jop, "protocol_identifier", p_id, NULL, e);
switch (desig_type) {
case 0: /* vendor specific */
- sgj_add_nv_hex_bytes(jsp, jop, "vendor_specific_hex", ip, dlen);
+ sgj_add_nv_hex_bytes(jsp, jop, "vendor_specific_hexbytes", ip, dlen);
break;
case 1: /* T10 vendor identification */
n = (dlen < 8) ? dlen : 8;
@@ -892,7 +1019,8 @@ sgj_get_designation_descriptor(sgj_state * jsp, sgj_opaque_p jop,
}
break;
case 3: /* NAA <n> */
- sgj_add_nv_hex_bytes(jsp, jop, "full_naa_in_hex", ip, dlen);
+ if (jsp->pr_hex)
+ sgj_add_nv_hex_bytes(jsp, jop, "full_naa_hexbytes", ip, dlen);
naa = (ip[0] >> 4) & 0xff;
switch (naa) {
case 2:
@@ -938,112 +1066,74 @@ sgj_get_designation_descriptor(sgj_state * jsp, sgj_opaque_p jop,
snprintf(b, blen, "unknown NAA value=0x%x", naa);
sgj_add_nv_ihexstr_ane(jsp, jop, "naa", naa, true, NULL, b,
naa_exp);
+ sgj_add_nv_hex_bytes(jsp, jop, "full_naa_hexbytes", ip, dlen);
break;
}
break;
-#if 0
case 4: /* Relative target port */
- if ((1 != c_set) || (1 != assoc) || (4 != dlen)) {
- n += sg_scnpr(b + n, blen - n, "%s << expected binary "
- "code_set, target port association, length 4 >>\n",
- lip);
- n += hex2str(ip, dlen, "", 1, blen - n, b + n);
- break;
- }
- d_id = sg_get_unaligned_be16(ip + 2);
- n += sg_scnpr(b + n, blen - n, "%s Relative target port: 0x%x\n",
- lip, d_id);
+ if (jsp->pr_hex)
+ sgj_add_nv_hex_bytes(jsp, jop, "relative_target_port_hexbytes",
+ ip, dlen);
+ sgj_add_nv_ihex(jsp, jop, "relative_target_port_identifier",
+ sg_get_unaligned_be16(ip + 2));
break;
case 5: /* (primary) Target port group */
- if ((1 != c_set) || (1 != assoc) || (4 != dlen)) {
- n += sg_scnpr(b + n, blen - n, "%s << expected binary "
- "code_set, target port association, length 4 >>\n",
- lip);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- d_id = sg_get_unaligned_be16(ip + 2);
- n += sg_scnpr(b + n, blen - n, "%s Target port group: 0x%x\n",
- lip, d_id);
+ if (jsp->pr_hex)
+ sgj_add_nv_hex_bytes(jsp, jop, "target_port_group_hexbytes",
+ ip, dlen);
+ sgj_add_nv_ihex(jsp, jop, "target_port_group",
+ sg_get_unaligned_be16(ip + 2));
break;
case 6: /* Logical unit group */
- if ((1 != c_set) || (0 != assoc) || (4 != dlen)) {
- n += sg_scnpr(b + n, blen - n, "%s << expected binary "
- "code_set, logical unit association, length 4 >>\n",
- lip);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- d_id = sg_get_unaligned_be16(ip + 2);
- n += sg_scnpr(b + n, blen - n, "%s Logical unit group: 0x%x\n",
- lip, d_id);
+ if (jsp->pr_hex)
+ sgj_add_nv_hex_bytes(jsp, jop, "logical_unit_group_hexbytes",
+ ip, dlen);
+ sgj_add_nv_ihex(jsp, jop, "logical_unit_group",
+ sg_get_unaligned_be16(ip + 2));
break;
case 7: /* MD5 logical unit identifier */
- if ((1 != c_set) || (0 != assoc)) {
- n += sg_scnpr(b + n, blen - n, "%s << expected binary "
- "code_set, logical unit association >>\n", lip);
- n += hex2str(ip, dlen, "", 1, blen - n, b + n);
- break;
- }
- n += sg_scnpr(b + n, blen - n, "%s MD5 logical unit "
- "identifier:\n", lip);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
+ sgj_add_nv_hex_bytes(jsp, jop, "md5_logical_unit_hexbytes",
+ ip, dlen);
break;
case 8: /* SCSI name string */
- if (3 != c_set) { /* accept ASCII as subset of UTF-8 */
- if (2 == c_set) {
- if (do_long)
- n += sg_scnpr(b + n, blen - n, "%s << expected "
- "UTF-8, use ASCII >>\n", lip);
- } else {
- n += sg_scnpr(b + n, blen - n, "%s << expected UTF-8 "
- "code_set >>\n", lip);
- n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
- break;
- }
- }
- n += sg_scnpr(b + n, blen - n, "%s SCSI name string:\n", lip);
- /* does %s print out UTF-8 ok??
- * Seems to depend on the locale. Looks ok here with my
- * locale setting: en_AU.UTF-8
- */
- n += sg_scnpr(b + n, blen - n, "%s %.*s\n", lip, dlen,
- (const char *)ip);
+ if (jsp->pr_hex)
+ sgj_add_nv_hex_bytes(jsp, jop, "scsi_name_string_hexbytes",
+ ip, dlen);
+ snprintf(b, blen, "%s", ip);
+ sgj_add_nv_s(jsp, jop, "scsi_name_string", b);
break;
case 9: /* Protocol specific port identifier */
- /* added in spc4r36, PIV must be set, proto_id indicates */
- /* whether UAS (USB) or SOP (PCIe) or ... */
- if (! piv)
- n += sg_scnpr(b + n, blen - n, " %s >>>> Protocol specific "
- "port identifier expects protocol\n%s "
- "identifier to be valid and it is not\n", lip, lip);
+ if (jsp->pr_hex)
+ sgj_add_nv_hex_bytes(jsp, jop,
+ "protocol_specific_port_identifier_hexbytes",
+ ip, dlen);
if (TPROTO_UAS == p_id) {
- n += sg_scnpr(b + n, blen - n, "%s USB device address: "
- "0x%x\n", lip, 0x7f & ip[0]);
- n += sg_scnpr(b + n, blen - n, "%s USB interface number: "
- "0x%x\n", lip, ip[2]);
+ jo2p = sgj_new_named_object(jsp, jop,
+ "usb_target_port_identifier");
+ sgj_add_nv_ihex(jsp, jo2p, "device_address", 0x7f & ip[0]);
+ sgj_add_nv_ihex(jsp, jo2p, "interface_number", ip[2]);
} else if (TPROTO_SOP == p_id) {
- n += sg_scnpr(b + n, blen - n, "%s PCIe routing ID, bus "
- "number: 0x%x\n", lip, ip[0]);
- n += sg_scnpr(b + n, blen - n, "%s function number: "
- "0x%x\n", lip, ip[1]);
- n += sg_scnpr(b + n, blen - n, "%s [or device number: "
- "0x%x, function number: 0x%x]\n", lip,
- (0x1f & (ip[1] >> 3)), 0x7 & ip[1]);
+ jo2p = sgj_new_named_object(jsp, jop, "pci_express_routing_id");
+ sgj_add_nv_ihex(jsp, jo2p, "routing_id",
+ sg_get_unaligned_be16(ip + 0));
} else
- n += sg_scnpr(b + n, blen - n, "%s >>>> unexpected protocol "
- "identifier: %s\n%s with Protocol "
- "specific port identifier\n", lip,
- sg_get_trans_proto_str(p_id, elen, e), lip);
+ sgj_add_nv_s(jsp, jop, "protocol_specific_port_identifier",
+ "decoding failure");
+
break;
case 0xa: /* UUID identifier */
- n += sg_t10_uuid_desig2str(ip, dlen, c_set, do_long, false, lip,
- blen - n, b + n);
+ if (jsp->pr_hex)
+ sgj_add_nv_hex_bytes(jsp, jop, "uuid_hexbytes",
+ ip, dlen);
+ sg_t10_uuid_desig2str(ip, dlen, c_set, false, true, NULL, blen, b);
+ n = strlen(b);
+ if ((n > 0) && ('\n' == b[n - 1]))
+ b[n - 1] = '\0';
+ sgj_add_nv_s(jsp, jop, "uuid", b);
break;
-#endif
default: /* reserved */
- hex2str(ip, dlen, NULL, 1, blen, b);
- sgj_add_nv_s(jsp, jop, "reserved_designator_hex", b);
+ sgj_add_nv_hex_bytes(jsp, jop, "reserved_designator_hexbytes",
+ ip, dlen);
break;
}
return true;
@@ -1226,6 +1316,15 @@ sgj_uds_referral_descriptor(sgj_state * jsp, sgj_opaque_p jop,
return true;
}
+/* Copy of static array in sg_lib.c */
+static const char * dd_usage_reason_str_arr[] = {
+ "Unknown",
+ "resend this and further commands to:",
+ "resend this command to:",
+ "new subsidiary lu added to this administrative lu:",
+ "administrative lu associated with a preferred binding:",
+ };
+
static bool
sgj_get_sense_descriptors(sgj_state * jsp, sgj_opaque_p jop,
const struct sg_scsi_sense_hdr * sshp,
@@ -1233,11 +1332,10 @@ sgj_get_sense_descriptors(sgj_state * jsp, sgj_opaque_p jop,
{
bool processed = true;
int add_sb_len, desc_len, k, dt, sense_key, n, sds;
-#if 0
uint16_t sct_sc;
-#endif
uint64_t ull;
const uint8_t * descp;
+ const char * cp;
sgj_opaque_p jap, jo2p, jo3p;
char b[80];
static const int blen = sizeof(b);
@@ -1409,7 +1507,7 @@ sgj_get_sense_descriptors(sgj_state * jsp, sgj_opaque_p jop,
break;
}
sgj_add_nv_ihex_ane(jsp, jo2p, "fsdt", !! (0x80 & descp[2]),
- NULL, "Forwarded Sense Data Truncated");
+ false, "Forwarded Sense Data Truncated");
sds = (0x7 & descp[2]);
if (sds < 1)
snprintf(b, blen, "%s [%d]", "Unknown", sds);
@@ -1429,7 +1527,7 @@ sgj_get_sense_descriptors(sgj_state * jsp, sgj_opaque_p jop,
break;
case 0xd: /* Added in SBC-3 rev 36d */
/* this descriptor combines descriptors 0, 1, 2 and 3 */
- sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", 0xc, NULL,
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
"Direct-access block device");
if (add_d_len < 28) {
sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
@@ -1438,7 +1536,7 @@ sgj_get_sense_descriptors(sgj_state * jsp, sgj_opaque_p jop,
}
sgj_add_nv_i(jsp, jo2p, "valid", (0x80 & descp[2]));
sgj_add_nv_ihex_ane(jsp, jo2p, "ili", !! (0x20 & descp[2]),
- NULL, "Incorrect Length Indicator");
+ false, "Incorrect Length Indicator");
processed = sgj_decode_sks(jsp, jo2p, descp + 4, desc_len - 4,
sense_key);
sgj_add_nv_ihex(jsp, jo2p, "field_replaceable_unit_code",
@@ -1448,77 +1546,59 @@ sgj_get_sense_descriptors(sgj_state * jsp, sgj_opaque_p jop,
sgj_add_nv_ihex(jsp, jo2p, "command_specific_information",
sg_get_unaligned_be64(descp + 16));
break;
-#if 0
case 0xe: /* Added in SPC-5 rev 6 (for Bind/Unbind) */
- n += sg_scnpr(b + n, blen - n, "Device designation\n");
- j = (int)SG_ARRAY_SIZE(dd_usage_reason_str_arr);
- if (descp[3] < j)
- n += sg_scnpr(b + n, blen - n, "%s Usage reason: %s\n",
- lip, dd_usage_reason_str_arr[descp[3]]);
- else
- n += sg_scnpr(b + n, blen - n, "%s Usage reason: "
- "reserved[%d]\n", lip, descp[3]);
- n += sg_get_designation_descriptor_str(z, descp + 4, descp[1] - 2,
- true, false, blen - n,
- b + n);
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Device designation");
+ n = descp[3];
+ cp = (n < (int)SG_ARRAY_SIZE(dd_usage_reason_str_arr)) ?
+ dd_usage_reason_str_arr[n] : "Unknown (reserved)";
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_usage_reason",
+ n, NULL, cp);
+ jo3p = sgj_new_named_object(jsp, jo2p,
+ "device_designation_descriptor");
+ sgj_get_designation_descriptor(jsp, jo3p, descp + 4,
+ desc_len - 4);
break;
case 0xf: /* Added in SPC-5 rev 10 (for Write buffer) */
- n += sg_scnpr(b + n, blen - n, "Microcode activation ");
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Microcode activation");
if (add_d_len < 6) {
sgj_add_nv_s(jsp, jop, parsing, dtsp);
processed = false;
break;
}
- progress = sg_get_unaligned_be16(descp + 6);
- n += sg_scnpr(b + n, blen - n, "time: ");
- if (0 == progress)
- n += sg_scnpr(b + n, blen - n, "unknown\n");
- else
- n += sg_scnpr(b + n, blen - n, "%d seconds\n", progress);
+ sgj_add_nv_ihex(jsp, jo2p, "microcode_activation_time",
+ sg_get_unaligned_be16(descp + 6));
break;
case 0xde: /* NVME Status Field; vendor (sg3_utils) specific */
- n += sg_scnpr(b + n, blen - n, "NVMe Status: ");
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "NVME status (sg3_utils)");
if (add_d_len < 6) {
sgj_add_nv_s(jsp, jop, parsing, dtsp);
processed = false;
break;
}
- n += sg_scnpr(b + n, blen - n, "DNR=%d, M=%d, ",
- (int)!!(0x80 & descp[5]), (int)!!(0x40 & descp[5]));
+ sgj_add_nv_ihex_ane(jsp, jo2p, "dnr", !! (0x80 & descp[5]),
+ false, "Do not retry");
+ sgj_add_nv_ihex_ane(jsp, jo2p, "m", !! (0x40 & descp[5]),
+ false, "More");
sct_sc = sg_get_unaligned_be16(descp + 6);
- n += sg_scnpr(b + n, blen - n, "SCT_SC=0x%x\n", sct_sc);
- if (sct_sc > 0) {
- char d[80];
-
- n += sg_scnpr(b + n, blen - n, " %s\n",
- sg_get_nvme_cmd_status_str(sct_sc, sizeof(d), d));
- }
+ sgj_add_nv_ihexstr_ane
+ (jsp, jo2p, "sct_sc", sct_sc, true, NULL,
+ sg_get_nvme_cmd_status_str(sct_sc, blen, b),
+ "Status Code Type (upper 8 bits) and Status Code");
break;
-#endif
default:
if (dt >= 0x80)
sgj_add_nv_ihex(jsp, jo2p, "vendor_specific_descriptor_type",
dt);
else
sgj_add_nv_ihex(jsp, jo2p, "unknown_descriptor_type", dt);
+ sgj_add_nv_hex_bytes(jsp, jo2p, "descriptor_hexbytes",
+ descp, desc_len);
processed = false;
break;
}
-#if 0
- if (! processed) {
- if (add_d_len > 0) {
- n += sg_scnpr(b + n, blen - n, "%s ", lip);
- for (j = 0; j < add_d_len; ++j) {
- if ((j > 0) && (0 == (j % 24)))
- n += sg_scnpr(b + n, blen - n, "\n%s ", lip);
- n += sg_scnpr(b + n, blen - n, "%02x ", descp[j + 2]);
- }
- n += sg_scnpr(b + n, blen - n, "\n");
- }
- }
- if (add_d_len < 0)
- n += sg_scnpr(b + n, blen - n, "%s short descriptor\n", lip);
-#endif
sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
}
return processed;
diff --git a/scripts/rescan-scsi-bus.sh b/scripts/rescan-scsi-bus.sh
index 27cc35cd..f7e363e8 100755
--- a/scripts/rescan-scsi-bus.sh
+++ b/scripts/rescan-scsi-bus.sh
@@ -4,7 +4,7 @@
# (c) 2006--2022 Hannes Reinecke, GNU GPL v2 or later
# $Id: rescan-scsi-bus.sh,v 1.57 2012/03/31 14:08:48 garloff Exp $
-VERSION="20220420"
+VERSION="20220622"
SCAN_WILD_CARD=4294967295
setcolor ()
diff --git a/src/sg_decode_sense.c b/src/sg_decode_sense.c
index 160544be..4f503033 100644
--- a/src/sg_decode_sense.c
+++ b/src/sg_decode_sense.c
@@ -30,7 +30,7 @@
#include "sg_unaligned.h"
-static const char * version_str = "1.27 20220624";
+static const char * version_str = "1.28 20220626";
#define MY_NAME "sg_decode_sense"
@@ -118,8 +118,7 @@ usage()
" --inhex=HFN|-i HFN same as action as --file=HFN\n"
" --json[=JO]|-j[JO] output in JSON instead of human "
"readable text.\n"
- " Optional argument JO see sg3_utils "
- "manpage\n"
+ " Use --json=? for JSON help\n"
" --nodecode|-N do not decode, may be neither sense "
"nor cdb\n"
" --nospace|-n no spaces or other separators between "
@@ -204,8 +203,15 @@ parse_cmd_line(struct opts_t *op, int argc, char *argv[])
break;
case 'j':
if (! sgj_init_state(&op->json_st, optarg)) {
- pr2serr("bad argument to --json= option, unrecognized "
- "character '%c'\n", op->json_st.first_bad_char);
+ int bad_char = op->json_st.first_bad_char;
+ char e[1500];
+
+ if (bad_char) {
+ pr2serr("bad argument to --json= option, unrecognized "
+ "character '%c'\n\n", bad_char);
+ }
+ sg_json_usage(0, e, sizeof(e));
+ pr2serr("%s", e);
return SG_LIB_SYNTAX_ERROR;
}
break;
@@ -327,7 +333,6 @@ main(int argc, char *argv[])
const char * cp;
sgj_state * jsp;
sgj_opaque_p jop = NULL;
- sgj_opaque_p jo2p;
char b[2048];
struct opts_t opts;
@@ -498,12 +503,18 @@ main(int argc, char *argv[])
sg_get_opcode_sa_name(opcode, sa, 0, blen, b);
printf("%s\n", b);
} else {
- if (as_json)
+ if (as_json) {
sgj_get_sense(jsp, jop, op->sense, op->sense_len);
- else
+ if (jsp->pr_output) {
+ sg_get_sense_str(NULL, op->sense, op->sense_len,
+ op->verbose, blen, b);
+ sgj_pr_str_output(jsp, b, strlen(b));
+ }
+ } else {
sg_get_sense_str(NULL, op->sense, op->sense_len,
op->verbose, blen, b);
- printf("%s\n", b);
+ printf("%s\n", b);
+ }
}
}
fini:
@@ -511,10 +522,13 @@ fini:
#if 0
// <<<< testing
+{
+ sgj_opaque_p jo2p;
+
// uint8_t dd[] = {0x1, 0x0, 0x0, 0x6, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
-uint8_t dd[] = {0x01, 0x00, 0x00, 0x16, 0x11, 0x22, 0x33, 0x44 , 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
- 0xdd, 0xee, 0xff, 0xed, 0xcb, 0xa9, 0x87, 0x65 , 0x43, 0x21};
+// uint8_t dd[] = {0x01, 0x00, 0x00, 0x16, 0x11, 0x22, 0x33, 0x44 , 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
+// 0xdd, 0xee, 0xff, 0xed, 0xcb, 0xa9, 0x87, 0x65 , 0x43, 0x21};
// uint8_t dd[] = {0x2, 0x1, 0x0, 0x14,
// 0x41, 0x42, 0x43, 0x20, 0x20, 0x20, 0x20, 0x20,
@@ -523,8 +537,11 @@ uint8_t dd[] = {0x01, 0x00, 0x00, 0x16, 0x11, 0x22, 0x33, 0x44 , 0x55, 0x66, 0x7
// uint8_t dd[] = {0x01, 0x03, 0x00, 0x08, 0x51, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
// uint8_t dd[] = {0x01, 0x03, 0x00, 0x10, 0x61, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0xee, 0xdd};
+uint8_t dd[] = {0x01, 0x14, 0x00, 0x04, 0x0, 0x0, 0x0, 0x2, };
+
jo2p = sgj_new_named_object(jsp, jop, "designation_descriptor");
sgj_get_designation_descriptor(jsp, jo2p, dd, sizeof(dd));
+}
// <<<< end of testing
#endif
diff --git a/src/sg_get_elem_status.c b/src/sg_get_elem_status.c
index fc46608a..4501a935 100644
--- a/src/sg_get_elem_status.c
+++ b/src/sg_get_elem_status.c
@@ -37,7 +37,7 @@
* given SCSI device.
*/
-static const char * version_str = "1.11 20220616"; /* sbc5r01 */
+static const char * version_str = "1.12 20220626"; /* sbc5r01 */
#define MY_NAME "sg_get_elem_status"
@@ -111,6 +111,7 @@ usage()
"in binary\n"
" --json[=JO]|-j[JO] output in JSON instead of human "
"readable text\n"
+ " use --json=? for JSON help\n"
" --maxlen=LEN|-m LEN max response length (allocation "
"length in cdb)\n"
" (def: 0 -> %d bytes)\n",
@@ -337,8 +338,15 @@ main(int argc, char * argv[])
break;
case 'j':
if (! sgj_init_state(&json_st, optarg)) {
- pr2serr("bad argument to --json= option, unrecognized "
- "character '%c'\n", json_st.first_bad_char);
+ int bad_char = json_st.first_bad_char;
+ char e[1500];
+
+ if (bad_char) {
+ pr2serr("bad argument to --json= option, unrecognized "
+ "character '%c'\n\n", bad_char);
+ }
+ sg_json_usage(0, e, sizeof(e));
+ pr2serr("%s", e);
return SG_LIB_SYNTAX_ERROR;
}
break;
diff --git a/src/sg_get_lba_status.c b/src/sg_get_lba_status.c
index 1612aaac..d85c5231 100644
--- a/src/sg_get_lba_status.c
+++ b/src/sg_get_lba_status.c
@@ -35,7 +35,7 @@
* device.
*/
-static const char * version_str = "1.27 20220616"; /* sbc5r01 */
+static const char * version_str = "1.28 20220626"; /* sbc5r01 */
#define MY_NAME "sg_get_lba_status"
@@ -106,7 +106,8 @@ usage()
" assumed to be ASCII hex or, if --raw, "
"in binary\n"
" --json[=JO]|-j[JO] output in JSON instead of human "
- "readable text\n"
+ "readable text.\n"
+ " Use --json=? for JSON help\n"
" --lba=LBA|-l LBA starting LBA (logical block address) "
"(def: 0)\n"
" --maxlen=LEN|-m LEN max response length (allocation "
@@ -291,8 +292,15 @@ main(int argc, char * argv[])
break;
case 'j':
if (! sgj_init_state(&json_st, optarg)) {
- pr2serr("bad argument to --json= option, unrecognized "
- "character '%c'\n", json_st.first_bad_char);
+ int bad_char = json_st.first_bad_char;
+ char e[1500];
+
+ if (bad_char) {
+ pr2serr("bad argument to --json= option, unrecognized "
+ "character '%c'\n\n", bad_char);
+ }
+ sg_json_usage(0, e, sizeof(e));
+ pr2serr("%s", e);
return SG_LIB_SYNTAX_ERROR;
}
break;
diff --git a/src/sg_opcodes.c b/src/sg_opcodes.c
index 4eaa5bae..8e29ea30 100644
--- a/src/sg_opcodes.c
+++ b/src/sg_opcodes.c
@@ -33,7 +33,7 @@
#include "sg_pt.h"
-static const char * version_str = "0.83 20220616"; /* spc6r06 */
+static const char * version_str = "0.84 20220626"; /* spc6r06 */
#define MY_NAME "sg_opcodes"
@@ -137,8 +137,7 @@ usage()
" instead of DEVICE which is ignored\n"
" --json[=JO]|-jJO output in JSON instead of human "
"readable\n"
- " text. Optional argument JO see manpage "
- "sg3_utils\n"
+ " test. Use --json=? for JSON help\n"
" --mask|-m show cdb usage data (a mask) when "
"all listed\n"
" --mlu|-M show MLU bit when all listed\n"
@@ -368,8 +367,15 @@ new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
break;
case 'j':
if (! sgj_init_state(&op->json_st, optarg)) {
- pr2serr("bad argument to --json= option, unrecognized "
- "character '%c'\n", op->json_st.first_bad_char);
+ int bad_char = op->json_st.first_bad_char;
+ char e[1500];
+
+ if (bad_char) {
+ pr2serr("bad argument to --json= option, unrecognized "
+ "character '%c'\n\n", bad_char);
+ }
+ sg_json_usage(0, e, sizeof(e));
+ pr2serr("%s", e);
return SG_LIB_SYNTAX_ERROR;
}
break;
@@ -1135,10 +1141,10 @@ main(int argc, char * argv[])
usage_old();
return 0;
}
- as_json = op->json_st.pr_as_json;
jsp = &op->json_st;
+ as_json = jsp->pr_as_json;
if (as_json) {
- jop = sgj_start(MY_NAME, version_str, argc, argv, &op->json_st);
+ jop = sgj_start(MY_NAME, version_str, argc, argv, jsp);
}
#ifdef DEBUG
pr2serr("In DEBUG mode, ");
@@ -1487,7 +1493,7 @@ err_out:
res = (res >= 0) ? res : SG_LIB_CAT_OTHER;
if (as_json) {
if (0 == op->do_hex)
- sgj_pr2file(&op->json_st, NULL, res, stdout);
+ sgj_pr2file(jsp, NULL, res, stdout);
sgj_finish(jsp);
}
return res;
diff --git a/src/sg_rep_zones.c b/src/sg_rep_zones.c
index a8d4cbc9..8fc733ff 100644
--- a/src/sg_rep_zones.c
+++ b/src/sg_rep_zones.c
@@ -40,7 +40,7 @@
* Based on zbc2r12.pdf
*/
-static const char * version_str = "1.39 20220616";
+static const char * version_str = "1.40 20220625";
#define MY_NAME "sg_rep_zones"
@@ -188,8 +188,7 @@ usage(int h)
" --inhex=FN|-i FN decode contents of FN, ignore DEVICE\n"
" --json[=JO]|-j[JO] output in JSON instead of human "
"readable text.\n"
- " Optional argument JO see sg3_utils "
- "manpage\n"
+ " Use --json=? for JSON help\n"
" --locator=LBA|-l LBA similar to --start= option\n"
" --maxlen=LEN|-m LEN max response length (allocation "
"length in cdb)\n"
@@ -1216,8 +1215,15 @@ main(int argc, char * argv[])
break;
case 'j':
if (! sgj_init_state(&op->json_st, optarg)) {
- pr2serr("bad argument to --json= option, unrecognized "
- "character '%c'\n", op->json_st.first_bad_char);
+ int bad_char = op->json_st.first_bad_char;
+ char e[1500];
+
+ if (bad_char) {
+ pr2serr("bad argument to --json= option, unrecognized "
+ "character '%c'\n\n", bad_char);
+ }
+ sg_json_usage(0, e, sizeof(e));
+ pr2serr("%s", e);
return SG_LIB_SYNTAX_ERROR;
}
break;
@@ -1512,7 +1518,7 @@ the_end:
ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
if (as_json) {
if (0 == op->do_hex)
- sgj_pr2file(&op->json_st, NULL, ret, stdout);
+ sgj_pr2file(jsp, NULL, ret, stdout);
sgj_finish(jsp);
}
return ret;
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 20f74b5c..eaac5d31 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -31,6 +31,8 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
+#include "sg_vpd.h"
+
/* This utility program was originally written for the Linux OS SCSI subsystem.
This program fetches Vital Product Data (VPD) pages from the given
@@ -40,7 +42,9 @@
*/
-static const char * version_str = "1.71 20220608"; /* spc6r06 + sbc5r01 */
+static const char * version_str = "1.72 20220627"; /* spc6r06 + sbc5r01 */
+
+#define MY_NAME "sg_decode_sense"
/* standard VPD pages, in ascending page number order */
#define VPD_SUPPORTED_VPDS 0x0
@@ -105,64 +109,20 @@ static const char * version_str = "1.71 20220608"; /* spc6r06 + sbc5r01 */
#define DEF_PT_TIMEOUT 60 /* 60 seconds */
-/* These two structures are duplicates of those of the same name in
- * sg_vpd_vendor.c . <<< Take care that both are the same. >>> */
-struct opts_t {
- bool do_all;
- bool do_enum;
- bool do_force;
- bool do_long;
- bool do_quiet;
- bool verbose_given;
- bool version_given;
- int do_hex;
- int do_ident;
- int do_raw;
- int examine;
- int maxlen;
- int vend_prod_num;
- int verbose;
- int vpd_pn;
- const char * device_name;
- const char * page_str;
- const char * inhex_fn;
- const char * vend_prod;
-};
-
-struct svpd_values_name_t {
- int value; /* VPD page number */
- int subvalue; /* to differentiate if value+pdt are not unique */
- int pdt; /* peripheral device type id, -1 is the default */
- /* (all or not applicable) value */
- const char * acron;
- const char * name;
-};
-
+uint8_t * rsp_buff;
-/* Following functions also used by sg_vpd_vendor.c hence extern */
-void svpd_enumerate_vendor(int vend_prod_num);
-int svpd_count_vendor_vpds(int vpd_pn, int vend_prod_num);
-int svpd_decode_vendor(int sg_fd, struct opts_t * op, int off);
-const struct svpd_values_name_t * svpd_find_vendor_by_acron(const char * ap);
-int svpd_find_vp_num_by_acron(const char * vp_ap);
-const struct svpd_values_name_t * svpd_find_vendor_by_num(int page_num,
- int vend_prod_num);
-int vpd_fetch_page(int sg_fd, uint8_t * rp, int page, int mxlen,
- bool qt, int vb, int * rlenp);
-void dup_sanity_chk(int sz_opts_t, int sz_values_name_t);
-
-static int svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue,
- int off, const char * prefix);
+static int svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
+ int subvalue, int off, const char * prefix);
static int svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue,
int off);
static int decode_dev_ids(const char * print_if_found, int num_leading,
uint8_t * buff, int len, int m_assoc,
int m_desig_type, int m_code_set,
- const struct opts_t * op);
+ struct opts_t * op, sgj_opaque_p jop);
+
+static const int rsp_buff_sz = MX_ALLOC_LEN + 2;
-uint8_t * rsp_buff;
-const int rsp_buff_sz = MX_ALLOC_LEN + 2;
static uint8_t * free_rsp_buff;
static struct option long_options[] = {
@@ -174,6 +134,7 @@ static struct option long_options[] = {
{"hex", no_argument, 0, 'H'},
{"ident", no_argument, 0, 'i'},
{"inhex", required_argument, 0, 'I'},
+ {"json", optional_argument, 0, 'j'},
{"long", no_argument, 0, 'l'},
{"maxlen", required_argument, 0, 'm'},
{"page", required_argument, 0, 'p'},
@@ -280,6 +241,9 @@ usage()
"DEVICE;\n"
" if used with --raw then read binary "
"from FN\n"
+ " --json[=JO]|-j[JO] output in JSON instead of human "
+ "readable text.\n"
+ " Use --json=? for JSON help\n"
" --long|-l perform extra decoding\n"
" --maxlen=LEN|-m LEN max response length (allocation "
"length in cdb)\n"
@@ -539,8 +503,8 @@ std_inq_decode(uint8_t * b, int len, int verbose)
}
static void
-decode_id_vpd(uint8_t * buff, int len, int subvalue,
- const struct opts_t * op)
+decode_id_vpd(uint8_t * buff, int len, int subvalue, struct opts_t * op,
+ sgj_opaque_p jop)
{
int m_a, m_d, m_cs, blen;
uint8_t * b;
@@ -556,23 +520,23 @@ decode_id_vpd(uint8_t * buff, int len, int subvalue,
m_cs = -1;
if (0 == subvalue) {
decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_LU), 0, b, blen,
- VPD_ASSOC_LU, m_d, m_cs, op);
+ VPD_ASSOC_LU, m_d, m_cs, op, jop);
decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TPORT), 0, b, blen,
- VPD_ASSOC_TPORT, m_d, m_cs, op);
+ VPD_ASSOC_TPORT, m_d, m_cs, op, jop);
decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TDEVICE), 0, b, blen,
- VPD_ASSOC_TDEVICE, m_d, m_cs, op);
+ VPD_ASSOC_TDEVICE, m_d, m_cs, op, jop);
} else if (VPD_DI_SEL_AS_IS == subvalue)
- decode_dev_ids(NULL, 0, b, blen, m_a, m_d, m_cs, op);
+ decode_dev_ids(NULL, 0, b, blen, m_a, m_d, m_cs, op, jop);
else {
if (VPD_DI_SEL_LU & subvalue)
decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_LU), 0, b, blen,
- VPD_ASSOC_LU, m_d, m_cs, op);
+ VPD_ASSOC_LU, m_d, m_cs, op, jop);
if (VPD_DI_SEL_TPORT & subvalue)
decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TPORT), 0, b,
- blen, VPD_ASSOC_TPORT, m_d, m_cs, op);
+ blen, VPD_ASSOC_TPORT, m_d, m_cs, op, jop);
if (VPD_DI_SEL_TARGET & subvalue)
decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TDEVICE), 0,
- b, blen, VPD_ASSOC_TDEVICE, m_d, m_cs, op);
+ b, blen, VPD_ASSOC_TDEVICE, m_d, m_cs, op, jop);
}
}
@@ -685,7 +649,8 @@ decode_mode_policy_vpd(uint8_t * buff, int len, int do_hex)
/* VPD_SCSI_PORTS */
static void
-decode_scsi_ports_vpd(uint8_t * buff, int len, const struct opts_t * op)
+decode_scsi_ports_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jop)
{
int k, bump, rel_port, ip_tid_len, tpd_len;
uint8_t * bp;
@@ -735,7 +700,7 @@ decode_scsi_ports_vpd(uint8_t * buff, int len, const struct opts_t * op)
if ((0 == op->do_quiet) || (ip_tid_len > 0))
printf(" Target port descriptor(s):\n");
decode_dev_ids("", 2 /* leading spaces */, bp + bump + 4,
- tpd_len, VPD_ASSOC_TPORT, -1, -1, op);
+ tpd_len, VPD_ASSOC_TPORT, -1, -1, op, jop);
}
}
bump += tpd_len + 4;
@@ -944,15 +909,17 @@ decode_dev_ids_quiet(uint8_t * buff, int len, int m_assoc,
static int
decode_dev_ids(const char * print_if_found, int num_leading, uint8_t * buff,
int len, int m_assoc, int m_desig_type, int m_code_set,
- const struct opts_t * op)
+ struct opts_t * op, sgj_opaque_p jop)
{
+ bool printed, sgj_output;
int assoc, off, u, i_len;
- bool printed;
const uint8_t * bp;
+ sgj_state * jsp = &op->json_st;
char b[1024];
char sp[82];
+ static const int blen = sizeof(b);
- if (op->do_quiet)
+ if (op->do_quiet && (! jsp->pr_as_json))
return decode_dev_ids_quiet(buff, len, m_assoc, m_desig_type,
m_code_set);
if (num_leading > (int)(sizeof(sp) - 2))
@@ -979,17 +946,41 @@ decode_dev_ids(const char * print_if_found, int num_leading, uint8_t * buff,
" remaining response length=%d\n", (len - off));
return SG_LIB_CAT_MALFORMED;
}
+ sgj_output = false;
+ if (op->json_st.pr_as_json) {
+ sgj_opaque_p jo2p =
+ sgj_new_named_object(jsp, jop, "designation_descriptor");
+
+ sgj_get_designation_descriptor(jsp, jo2p, bp, i_len + 4);
+ if (jsp->pr_output)
+ sgj_output = true;
+ else
+ continue;
+ }
assoc = ((bp[1] >> 4) & 0x3);
if (print_if_found && (! printed)) {
printed = true;
- if (strlen(print_if_found) > 0)
- printf(" %s:\n", print_if_found);
+ if (strlen(print_if_found) > 0) {
+ snprintf(b, blen, " %s:", print_if_found);
+ if (sgj_output)
+ sgj_pr_str_output(jsp, b, strlen(b));
+ else
+ printf("%s\n", b);
+ }
+ }
+ if (NULL == print_if_found) {
+ snprintf(b, blen, " %s%s:", sp, sg_get_desig_assoc_str(assoc));
+ if (sgj_output)
+ sgj_pr_str_output(jsp, b, strlen(b));
+ else
+ printf("%s\n", b);
}
- if (NULL == print_if_found)
- printf(" %s%s:\n", sp, sg_get_desig_assoc_str(assoc));
sg_get_designation_descriptor_str(sp, bp, i_len + 4, false,
- op->do_long, sizeof(b), b);
- printf("%s", b);
+ op->do_long, blen, b);
+ if (sgj_output)
+ sgj_pr_str_output(jsp, b, strlen(b));
+ else
+ printf("%s", b);
}
if (-2 == u) {
pr2serr("VPD page error: short designator around offset %d\n", off);
@@ -1150,7 +1141,7 @@ decode_softw_inf_id(uint8_t * buff, int len, int do_hex)
len -= 4;
buff += 4;
for ( ; len > 5; len -= 6, buff += 6)
- printf(" IEEE identifier: 0x%" PRIx64 "\n",
+ printf(" IEEE identifier: 0x%" PRIx64 "\n",
sg_get_unaligned_be48(buff + 0));
}
@@ -1266,7 +1257,8 @@ static const char * constituent_type_arr[] = {
/* VPD_DEVICE_CONSTITUENTS 0x8b */
static void
-decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op)
+decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jop)
{
int k, j, res, bump, csd_len;
uint16_t constit_type;
@@ -1335,7 +1327,7 @@ decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op)
printf(" Constituent VPD page %d:\n", q + 1);
/* SPC-5 says these shall _not_ themselves be Device
* Constituent VPD pages. So no infinite recursion. */
- res = svpd_decode_t10(-1, op, 0, off, NULL);
+ res = svpd_decode_t10(-1, op, jop, 0, off, NULL);
if (SG_LIB_CAT_OTHER == res) {
res = svpd_decode_vendor(-1, op, off);
if (SG_LIB_CAT_OTHER == res)
@@ -2819,8 +2811,8 @@ svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
/* Returns 0 if successful. If don't know how to decode, returns
* SG_LIB_CAT_OTHER else see sg_ll_inquiry(). */
static int
-svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off,
- const char * prefix)
+svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
+ int subvalue, int off, const char * prefix)
{
bool allow_name, allow_if_found, long_notquiet, qt;
bool vpd_supported = false;
@@ -2997,7 +2989,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off,
printf(" [PQual=%d Peripheral device type: %s]\n",
(rp[0] & 0xe0) >> 5,
sg_get_pdt_str(pdt, sizeof(b), b));
- decode_id_vpd(rp, len, subvalue, op);
+ decode_id_vpd(rp, len, subvalue, op, jop);
}
return 0;
}
@@ -3108,7 +3100,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off,
printf(" [PQual=%d Peripheral device type: %s]\n",
(rp[0] & 0xe0) >> 5,
sg_get_pdt_str(pdt, sizeof(b), b));
- decode_scsi_ports_vpd(rp, len, op);
+ decode_scsi_ports_vpd(rp, len, op, jop);
}
return 0;
}
@@ -3175,7 +3167,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off,
if (op->do_raw)
dStrRaw(rp, len);
else
- decode_dev_constit_vpd(rp, len, op);
+ decode_dev_constit_vpd(rp, len, op, jop);
return 0;
}
break;
@@ -3626,7 +3618,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off,
}
static int
-svpd_decode_all(int sg_fd, struct opts_t * op)
+svpd_decode_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop)
{
int k, res, rlen, n, pn;
int max_pn = 255;
@@ -3670,7 +3662,7 @@ svpd_decode_all(int sg_fd, struct opts_t * op)
if (op->do_long)
printf("[0x%x] ", pn);
- res = svpd_decode_t10(sg_fd, op, 0, 0, NULL);
+ res = svpd_decode_t10(sg_fd, op, jop, 0, 0, NULL);
if (SG_LIB_CAT_OTHER == res) {
res = svpd_decode_vendor(sg_fd, op, 0);
if (SG_LIB_CAT_OTHER == res)
@@ -3721,7 +3713,7 @@ svpd_decode_all(int sg_fd, struct opts_t * op)
if (op->do_long)
printf("[0x%x] ", pn);
- res = svpd_decode_t10(-1, op, 0, off, NULL);
+ res = svpd_decode_t10(-1, op, jop, 0, off, NULL);
if (SG_LIB_CAT_OTHER == res) {
res = svpd_decode_vendor(-1, op, off);
if (SG_LIB_CAT_OTHER == res)
@@ -3733,7 +3725,7 @@ svpd_decode_all(int sg_fd, struct opts_t * op)
}
static int
-svpd_examine_all(int sg_fd, struct opts_t * op)
+svpd_examine_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop)
{
bool first = true;
bool got_one = false;
@@ -3756,7 +3748,7 @@ svpd_examine_all(int sg_fd, struct opts_t * op)
snprintf(b, sizeof(b), "[0x%x] ", k);
else
b[0] = '\0';
- res = svpd_decode_t10(sg_fd, op, 0, 0, b);
+ res = svpd_decode_t10(sg_fd, op, jop, 0, 0, b);
if (SG_LIB_CAT_OTHER == res) {
res = svpd_decode_vendor(sg_fd, op, 0);
if (SG_LIB_CAT_OTHER == res)
@@ -3783,24 +3775,25 @@ svpd_examine_all(int sg_fd, struct opts_t * op)
int
main(int argc, char * argv[])
{
+ bool as_json;
int c, res, matches;
int sg_fd = -1;
int inhex_len = 0;
int ret = 0;
int subvalue = 0;
const char * cp;
- struct opts_t * op;
+ sgj_state * jsp;
+ sgj_opaque_p jop = NULL;
const struct svpd_values_name_t * vnp;
- struct opts_t opts;
+ struct opts_t opts = {0};
+ struct opts_t * op = &opts;
- op = &opts;
- memset(&opts, 0, sizeof(opts));
dup_sanity_chk((int)sizeof(opts), (int)sizeof(*vnp));
op->vend_prod_num = -1;
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "aeEfhHiI:lm:M:p:qrvV", long_options,
+ c = getopt_long(argc, argv, "aeEfhHiI:j::lm:M:p:qrvV", long_options,
&option_index);
if (c == -1)
break;
@@ -3836,6 +3829,20 @@ main(int argc, char * argv[])
} else
op->inhex_fn = optarg;
break;
+ case 'j':
+ if (! sgj_init_state(&op->json_st, optarg)) {
+ int bad_char = op->json_st.first_bad_char;
+ char e[1500];
+
+ if (bad_char) {
+ pr2serr("bad argument to --json= option, unrecognized "
+ "character '%c'\n\n", bad_char);
+ }
+ sg_json_usage(0, e, sizeof(e));
+ pr2serr("%s", e);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
case 'l':
op->do_long = true;
break;
@@ -3972,6 +3979,12 @@ main(int argc, char * argv[])
}
return 0;
}
+
+ as_json = op->json_st.pr_as_json;
+ jsp = &op->json_st;
+ if (as_json)
+ jop = sgj_start(MY_NAME, version_str, argc, argv, jsp);
+
if (op->page_str) {
if ((0 == strcmp("-1", op->page_str)) ||
(0 == strcmp("-2", op->page_str)))
@@ -3984,7 +3997,8 @@ main(int argc, char * argv[])
pr2serr("abbreviation doesn't match a VPD page\n");
printf("Available standard VPD pages:\n");
enumerate_vpds(1, 1);
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto fini;
}
}
op->vpd_pn = vnp->value;
@@ -3995,14 +4009,16 @@ main(int argc, char * argv[])
if (cp && op->vend_prod) {
pr2serr("the --page=pg,vp and the --vendor=vp forms overlap, "
"choose one or the other\n");
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto fini;
}
op->vpd_pn = sg_get_num_nomult(op->page_str);
if ((op->vpd_pn < 0) || (op->vpd_pn > 255)) {
pr2serr("Bad page code value after '-p' option\n");
printf("Available standard VPD pages:\n");
enumerate_vpds(1, 1);
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto fini;
}
if (cp) {
if (isdigit((uint8_t)*(cp + 1)))
@@ -4014,7 +4030,8 @@ main(int argc, char * argv[])
"option\n");
if (op->vend_prod_num < 0)
svpd_enumerate_vendor(-1);
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto fini;
}
subvalue = op->vend_prod_num;
} else if (op->vend_prod) {
@@ -4027,7 +4044,8 @@ main(int argc, char * argv[])
pr2serr("Bad vendor/product acronym after '--vendor=' "
"option\n");
svpd_enumerate_vendor(-1);
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto fini;
}
subvalue = op->vend_prod_num;
}
@@ -4041,7 +4059,8 @@ main(int argc, char * argv[])
pr2serr("Bad vendor/product acronym after '--vendor=' "
"option\n");
svpd_enumerate_vendor(-1);
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto fini;
}
subvalue = op->vend_prod_num;
}
@@ -4050,7 +4069,8 @@ main(int argc, char * argv[])
false);
if (NULL == rsp_buff) {
pr2serr("Unable to allocate %d bytes on heap\n", rsp_buff_sz);
- return sg_convert_errno(ENOMEM);
+ ret = sg_convert_errno(ENOMEM);
+ goto fini;
}
if (op->inhex_fn) {
if (op->device_name) {
@@ -4126,9 +4146,9 @@ main(int argc, char * argv[])
if ((0 == op->maxlen) || (inhex_len < op->maxlen))
op->maxlen = inhex_len;
if (op->do_all)
- res = svpd_decode_all(-1, op);
+ res = svpd_decode_all(-1, op, jop);
else {
- res = svpd_decode_t10(-1, op, subvalue, 0, NULL);
+ res = svpd_decode_t10(-1, op, jop, subvalue, 0, NULL);
if (SG_LIB_CAT_OTHER == res) {
res = svpd_decode_vendor(-1, op, 0);
if (SG_LIB_CAT_OTHER == res)
@@ -4151,13 +4171,13 @@ main(int argc, char * argv[])
}
if (op->examine > 0) {
- ret = svpd_examine_all(sg_fd, op);
+ ret = svpd_examine_all(sg_fd, op, jop);
} else if (op->do_all)
- ret = svpd_decode_all(sg_fd, op);
+ ret = svpd_decode_all(sg_fd, op, jop);
else {
memset(rsp_buff, 0, rsp_buff_sz);
- res = svpd_decode_t10(sg_fd, op, subvalue, 0, NULL);
+ res = svpd_decode_t10(sg_fd, op, jop, subvalue, 0, NULL);
if (SG_LIB_CAT_OTHER == res) {
res = svpd_decode_vendor(sg_fd, op, 0);
if (SG_LIB_CAT_OTHER == res)
@@ -4183,12 +4203,19 @@ err_out:
pr2serr("Some error occurred, try again with '-v' or '-vv' for "
"more information\n");
}
+fini:
res = (sg_fd >= 0) ? sg_cmds_close_device(sg_fd) : 0;
if (res < 0) {
pr2serr("close error: %s\n", safe_strerror(-res));
if (0 == ret)
- return sg_convert_errno(-res);
+ ret = sg_convert_errno(-res);
+ }
+ ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+ if (as_json) {
+ if (0 == op->do_hex)
+ sgj_pr2file(jsp, NULL, ret, stdout);
+ sgj_finish(jsp);
}
- return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+ return ret;
}
diff --git a/src/sg_vpd.h b/src/sg_vpd.h
new file mode 100644
index 00000000..67205717
--- /dev/null
+++ b/src/sg_vpd.h
@@ -0,0 +1,79 @@
+#ifndef SG_VPD_H
+#define SG_VPD_H
+
+/*
+ * Copyright (c) 2022 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.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "sg_lib.h"
+#include "sg_pr2serr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* These two structures are duplicates of those of the same name in
+ * sg_vpd_vendor.c . <<< Take care that both are the same. >>> */
+struct opts_t {
+ bool do_all;
+ bool do_enum;
+ bool do_force;
+ bool do_long;
+ bool do_quiet;
+ bool verbose_given;
+ bool version_given;
+ int do_hex;
+ int do_ident;
+ int do_raw;
+ int examine;
+ int maxlen;
+ int vend_prod_num;
+ int verbose;
+ int vpd_pn;
+ const char * device_name;
+ const char * page_str;
+ const char * inhex_fn;
+ const char * vend_prod;
+ sgj_state json_st;
+};
+
+struct svpd_values_name_t {
+ int value; /* VPD page number */
+ int subvalue; /* to differentiate if value+pdt are not unique */
+ int pdt; /* peripheral device type id, -1 is the default */
+ /* (all or not applicable) value */
+ const char * acron;
+ const char * name;
+};
+
+void svpd_enumerate_vendor(int vend_prod_num);
+int svpd_count_vendor_vpds(int vpd_pn, int vend_prod_num);
+int svpd_decode_vendor(int sg_fd, struct opts_t * op, int off);
+const struct svpd_values_name_t * svpd_find_vendor_by_acron(const char * ap);
+int svpd_find_vp_num_by_acron(const char * vp_ap);
+const struct svpd_values_name_t * svpd_find_vendor_by_num(int page_num,
+ int vend_prod_num);
+int vpd_fetch_page(int sg_fd, uint8_t * rp, int page, int mxlen,
+ bool qt, int vb, int * rlenp);
+void dup_sanity_chk(int sz_opts_t, int sz_values_name_t);
+
+extern uint8_t * rsp_buff;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of SG_VPD_H */
diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c
index a1a1a501..1a607404 100644
--- a/src/sg_vpd_vendor.c
+++ b/src/sg_vpd_vendor.c
@@ -28,6 +28,8 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
+#include "sg_vpd.h"
+
/* This is a companion file to sg_vpd.c . It contains logic to output and
decode vendor specific VPD pages
@@ -98,46 +100,6 @@
#define DEF_ALLOC_LEN 252
#define MX_ALLOC_LEN (0xc000 + 0x80)
-/* These two structures are duplicates of those of the same name in
- * sg_vpd.c . <<< Take care that both are the same. >>> */
-struct opts_t {
- bool do_all;
- bool do_enum;
- bool do_force;
- bool do_long;
- bool do_quiet;
- bool verbose_given;
- bool version_given;
- int do_hex;
- int do_ident;
- int do_raw;
- int examine;
- int maxlen;
- int vend_prod_num;
- int verbose;
- int vpd_pn;
- const char * device_name;
- const char * page_str;
- const char * inhex_fn;
- const char * vend_prod;
-};
-
-struct svpd_values_name_t {
- int value; /* VPD page number */
- int subvalue; /* to differentiate if value+pdt are not unique */
- int pdt; /* peripheral device type id, -1 is the default */
- /* (all or not applicable) value */
- const char * acron;
- const char * name;
-};
-
-int vpd_fetch_page(int sg_fd, uint8_t * rp, int page, int mxlen,
- bool qt, int vb, int * rlenp);
-
-/* sharing large global buffer, defined in sg_vpd.c */
-extern uint8_t * rsp_buff;
-
-/* end of section copied from sg_vpd.c . Maybe sg_vpd.h is needed */
struct svpd_vp_name_t {
int vend_prod_num; /* vendor/product identifier */
diff --git a/testing/Makefile b/testing/Makefile
index aec375f6..2343cdee 100644
--- a/testing/Makefile
+++ b/testing/Makefile
@@ -87,7 +87,7 @@ sg_chk_asc: sg_chk_asc.o ../lib/sg_lib.o ../lib/sg_lib_data.o
sg_tst_nvme: sg_tst_nvme.o $(LIBFILESNEW)
$(LD) -o $@ $(LDFLAGS) $^
-tst_sg_lib: tst_sg_lib.o ../lib/sg_lib.o ../lib/sg_lib_data.o
+tst_sg_lib: tst_sg_lib.o $(LIBFILESNEW)
$(LD) -o $@ $(LDFLAGS) $^
sgs_dd: sgs_dd.o $(LIBFILESOLD)
diff --git a/testing/tst_sg_lib.c b/testing/tst_sg_lib.c
index eb159334..51c109ee 100644
--- a/testing/tst_sg_lib.c
+++ b/testing/tst_sg_lib.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2020 Douglas Gilbert.
+ * Copyright (c) 2013-2022 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.
@@ -44,9 +44,11 @@
* related to snprintf().
*/
-static const char * version_str = "1.14 20200901";
+static const char * version_str = "1.15 20220625";
+#define MY_NAME "tst_sg_lib"
+
#define MAX_LINE_LEN 1024
@@ -55,6 +57,7 @@ static struct option long_options[] = {
{"exit", no_argument, 0, 'e'},
{"help", no_argument, 0, 'h'},
{"hex2", no_argument, 0, 'H'},
+ {"json", optional_argument, 0, 'j'},
{"leadin", required_argument, 0, 'l'},
{"num", required_argument, 0, 'n'},
{"printf", no_argument, 0, 'p'},
@@ -136,7 +139,7 @@ static const uint8_t desc_sense_data5[] = {
};
static const uint8_t desc_sense_data6[] = {
- /* UA, req, subsidiary bindinganged */
+ /* UA, req, subsidiary binding */
0x72, 0x6, 0x3f, 0x1a, 0x0, 0x0, 0x0, 26+12+12,
/* 0xe: designator, reason: preferred admin lu, uuid */
0xe, 0x18, 0x0, 0x4, 0x1, 0xa, 0x0, 0x12,
@@ -215,6 +218,7 @@ static uint8_t arr[64];
int
main(int argc, char * argv[])
{
+ bool as_json = false;
bool do_exit_status = false;
bool ok;
int k, c, n, len;
@@ -227,6 +231,10 @@ main(int argc, char * argv[])
int did_something = 0;
int vb = 0;
int ret = 0;
+ sgj_opaque_p jop = NULL;
+ sgj_opaque_p jo2p;
+ sgj_state json_st = {0};
+ sgj_state * jsp = &json_st;
char b[2048];
char bb[256];
const int b_len = sizeof(b);
@@ -234,7 +242,7 @@ main(int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "b:ehHl:n:psuvV", long_options,
+ c = getopt_long(argc, argv, "b:ehHj::l:n:psuvV", long_options,
&option_index);
if (c == -1)
break;
@@ -258,6 +266,14 @@ main(int argc, char * argv[])
case 'H':
++do_hex2;
break;
+ case 'j':
+ if (! sgj_init_state(&json_st, optarg)) {
+ pr2serr("bad argument to --json= option, unrecognized "
+ "character '%c'\n", json_st.first_bad_char);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+
case 'l':
leadin = optarg;
break;
@@ -299,6 +315,10 @@ main(int argc, char * argv[])
}
}
+ as_json = json_st.pr_as_json;
+ if (as_json)
+ jop = sgj_start(MY_NAME, version_str, argc, argv, jsp);
+
if (do_exit_status) {
++did_something;
@@ -335,39 +355,87 @@ main(int argc, char * argv[])
if (do_sense ) {
++did_something;
- printf("desc_sense_data test1:\n");
- sg_print_sense(leadin, desc_sense_data1,
- (int)sizeof(desc_sense_data1), vb);
- printf("\n");
+ if (as_json) {
+ jo2p = sgj_new_named_object(jsp, jop, "desc_sense_data__test1");
+ sgj_get_sense(jsp, jo2p, desc_sense_data1,
+ (int)sizeof(desc_sense_data1));
+ } else {
+ printf("desc_sense_data test1:\n");
+ sg_print_sense(leadin, desc_sense_data1,
+ (int)sizeof(desc_sense_data1), vb);
+ printf("\n");
+ }
#if 1
- printf("sg_get_sense_str(ds_data1):\n");
- sg_get_sense_str(leadin, desc_sense_data1,
- sizeof(desc_sense_data1), vb, b_len, b);
- printf("sg_get_sense_str: strlen(b)->%u\n", (uint32_t)strlen(b));
- printf("%s", b);
- printf("\n");
+ if (as_json) {
+ sgj_pr_str_output(jsp, "sg_get_sense_str(ds_data1)", 999);
+ sg_get_sense_str(leadin, desc_sense_data1,
+ sizeof(desc_sense_data1), vb, b_len, b);
+ sgj_pr_str_output(jsp, b, strlen(b));
+
+ } else {
+ printf("sg_get_sense_str(ds_data1):\n");
+ sg_get_sense_str(leadin, desc_sense_data1,
+ sizeof(desc_sense_data1), vb, b_len, b);
+ printf("sg_get_sense_str: strlen(b)->%u\n", (uint32_t)strlen(b));
+ printf("%s", b);
+ printf("\n");
+ }
#endif
- printf("desc_sense_data test2\n");
- sg_print_sense(leadin, desc_sense_data2,
- (int)sizeof(desc_sense_data2), vb);
- printf("\n");
- printf("desc_sense block dev combo plus designator test3\n");
- sg_print_sense(leadin, desc_sense_data3,
- (int)sizeof(desc_sense_data3), vb);
- printf("\n");
- printf("desc_sense forwarded sense test4\n");
- sg_print_sense(leadin, desc_sense_data4,
- (int)sizeof(desc_sense_data4), vb);
- printf("\n");
- printf("desc_sense ATA Info test5\n");
- sg_print_sense(leadin, desc_sense_data5,
- (int)sizeof(desc_sense_data5), vb);
- printf("\n");
- printf("desc_sense UA subsidiary binding changed test6\n");
- sg_print_sense(leadin, desc_sense_data6,
- (int)sizeof(desc_sense_data6), vb);
- printf("\n");
- printf("\n");
+ if (as_json) {
+ jo2p = sgj_new_named_object(jsp, jop, "desc_sense_data__test2");
+ sgj_get_sense(jsp, jo2p, desc_sense_data2,
+ (int)sizeof(desc_sense_data2));
+ } else {
+ printf("desc_sense_data test2\n");
+ sg_print_sense(leadin, desc_sense_data2,
+ (int)sizeof(desc_sense_data2), vb);
+ printf("\n");
+ }
+ if (as_json) {
+ jo2p = sgj_new_named_object(jsp, jop,
+ "desc_sense_block_combo_test3");
+ sgj_get_sense(jsp, jo2p, desc_sense_data3,
+ (int)sizeof(desc_sense_data3));
+ } else {
+ printf("desc_sense block dev combo plus designator test3\n");
+ sg_print_sense(leadin, desc_sense_data3,
+ (int)sizeof(desc_sense_data3), vb);
+ printf("\n");
+ }
+ if (as_json) {
+ jo2p = sgj_new_named_object(jsp, jop,
+ "desc_sense_forwarded_sense_test4");
+ sgj_get_sense(jsp, jo2p, desc_sense_data4,
+ (int)sizeof(desc_sense_data4));
+ } else {
+ printf("desc_sense forwarded sense test4\n");
+ sg_print_sense(leadin, desc_sense_data4,
+ (int)sizeof(desc_sense_data4), vb);
+ printf("\n");
+ }
+ if (as_json) {
+ jo2p = sgj_new_named_object(jsp, jop,
+ "desc_sense_ata_info_test5");
+ sgj_get_sense(jsp, jo2p, desc_sense_data5,
+ (int)sizeof(desc_sense_data5));
+ } else {
+ printf("desc_sense ATA Info test5\n");
+ sg_print_sense(leadin, desc_sense_data5,
+ (int)sizeof(desc_sense_data5), vb);
+ printf("\n");
+ }
+ if (as_json) {
+ jo2p = sgj_new_named_object(jsp, jop,
+ "desc_sense_ua_binding_test6");
+ sgj_get_sense(jsp, jo2p, desc_sense_data6,
+ (int)sizeof(desc_sense_data6));
+ } else {
+ printf("desc_sense UA subsidiary binding changed test6\n");
+ sg_print_sense(leadin, desc_sense_data6,
+ (int)sizeof(desc_sense_data6), vb);
+ printf("\n");
+ printf("\n");
+ }
}
if (do_printf) {
@@ -459,7 +527,7 @@ main(int argc, char * argv[])
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58};
++did_something;
- for (k = 0; k < 18; ++k) {
+ for (k = 0; k < 19; ++k) {
printf("k=%d:\n", k);
hex2stdout(b, k, 0);
hex2str(b, k, "h2str0: ", 0, sizeof(bb), bb);
@@ -467,6 +535,8 @@ main(int argc, char * argv[])
hex2stdout(b, k, 1);
hex2str(b, k, "h2str1: ", 1, sizeof(bb), bb);
printf("%s", bb);
+ hex2str(b, k, "h2str2: ", 2, sizeof(bb), bb);
+ printf("%s\n", bb);
hex2stdout(b, k, -1);
printf("\n");
}
@@ -654,5 +724,11 @@ main(int argc, char * argv[])
if (0 == did_something)
printf("Looks like no tests done, check usage with '-h'\n");
+ ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+ if (as_json) {
+ if (0 == do_hex2)
+ sgj_pr2file(jsp, NULL, ret, stdout);
+ sgj_finish(jsp);
+ }
return ret;
}