aboutsummaryrefslogtreecommitdiff
path: root/src/sg_vpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sg_vpd.c')
-rw-r--r--src/sg_vpd.c233
1 files changed, 130 insertions, 103 deletions
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;
}