diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/sg_decode_sense.c | 39 | ||||
-rw-r--r-- | src/sg_get_elem_status.c | 14 | ||||
-rw-r--r-- | src/sg_get_lba_status.c | 16 | ||||
-rw-r--r-- | src/sg_opcodes.c | 22 | ||||
-rw-r--r-- | src/sg_rep_zones.c | 18 | ||||
-rw-r--r-- | src/sg_vpd.c | 233 | ||||
-rw-r--r-- | src/sg_vpd.h | 79 | ||||
-rw-r--r-- | src/sg_vpd_vendor.c | 42 |
8 files changed, 288 insertions, 175 deletions
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 */ |