Skip to content

Commit

Permalink
sg_inq+sg_vpd: more JSON work (add SG_C_CPP_ZERO_INIT)
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@966 6180dd3e-e324-4e3e-922d-17de1ae2f315
  • Loading branch information
doug-gilbert committed Aug 12, 2022
1 parent 4ea97e6 commit 048bd12
Show file tree
Hide file tree
Showing 68 changed files with 1,209 additions and 1,374 deletions.
6 changes: 5 additions & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -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 [20220805] [svn: r964]
Changelog for pre-release sg3_utils-1.48 [20220811] [svn: r966]
- some utilities: add experimental --json[=JO] option
- sg_z_act_query: new utility for sending either a
Zone activate or Zone query command
Expand All @@ -23,6 +23,8 @@ Changelog for pre-release sg3_utils-1.48 [20220805] [svn: r964]
applied with tweaks: add timeout parameter
- clean $norm handling
- fix handling of '-I <secs>' option
- sgdevice26: do not traverse sg class if scsi_device
is not added
- sg_rep_zones: add Report zone starting LBA granularity
field in REPORT ZONES response [zbc2r12]
- add --brief option, show part of header and last
Expand Down Expand Up @@ -65,6 +67,8 @@ Changelog for pre-release sg3_utils-1.48 [20220805] [svn: r964]
- cleanup masks for PDT [0x1f] and group_number [0x3f]
- new sg_json_builder.[hc] files local to lib folder
- document internal json interface in include/sg_pr2serr.h
- add SG_C_CPP_ZERO_INIT to better handle aggregate stack
instance zeroing (C23 adding 'struct T t {};' will help)
- initialize all sense buffers to 0
- rework main README file
- rev 921+922 are bugfix revs on release 1.47 [r919,920]
Expand Down
10 changes: 9 additions & 1 deletion include/sg_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ extern "C" {
/* Borrowed from Linux kernel; no check that 'arr' actually is one */
#define SG_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

/* Doesn't seem to be a common C and C++ technique for clearing an
* aggregrate (e.g. a struct instance) on the stack. Hence this hack: */
#ifdef __cplusplus
#define SG_C_CPP_ZERO_INIT {}
#else
#define SG_C_CPP_ZERO_INIT ={0}
#endif


/* The format of the version string is like this: "2.26 20170906" */
const char * sg_lib_version();
Expand Down Expand Up @@ -628,7 +636,7 @@ void dStrHex(const char * str, int len, int no_ascii);
void dStrHexErr(const char * str, int len, int no_ascii);

/* Read binary starting at 'str' for 'len' bytes and output as ASCII
* hexadecinal into file pointer (fp). 16 bytes per line are output with an
* hexadecimal into file pointer (fp). 16 bytes per line are output with an
* additional space between 8th and 9th byte on each line (for readability).
* 'no_ascii' selects one of 3 output format types as shown in dStrHex() . */
void dStrHexFp(const char* str, int len, int no_ascii, FILE * fp);
Expand Down
79 changes: 40 additions & 39 deletions include/sg_pr2serr.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ int pr2serr(const char * fmt, ...) __printf(1, 2);
int pr2ws(const char * fmt, ...) __printf(1, 2);

/* Want safe, 'n += snprintf(b + n, blen - n, ...)' style sequence of
* functions that can be called mulriple times. Returns number of chars
* functions that can be called multiple times. Returns number of chars
* placed in cp excluding the trailing null char. So for cp_max_len > 0 the
* return value is always < cp_max_len; for cp_max_len <= 1 the return value
* is 0 and no chars are written to cp. Note this means that when
Expand All @@ -63,13 +63,13 @@ enum sgj_separator_t {

typedef void * sgj_opaque_p;

/* Apart from the pointers at the end the other fields are initialized
* from the argument given to --json= . If there is no argument then
* they initialized as shown. */
/* Apart from the state information at the end of this structure, the earlier
* fields are initialized from the command line argument given to the
* --json= option. If there is no argument then they initialized as shown. */
typedef struct sgj_state_t {
/* the following set by default, the SG3_UTILS_JSON_OPTS envirinment
/* the following set by default, the SG3_UTILS_JSON_OPTS environment
* variable or command line argument to --json option, in that order. */
bool pr_as_json; /* = false */
bool pr_as_json; /* = false (def: is human readable output) */
bool pr_exit_status; /* 'e' (def: true) */
bool pr_hex; /* 'h' (def: false) */
bool pr_leadin; /* 'l' (def: true) */
Expand All @@ -81,6 +81,7 @@ typedef struct sgj_state_t {
char pr_format; /* (def: '\0') */
int pr_indent_size; /* digit (def: 4) */
int verbose; /* 'v' (def: 0) incremented each appearance */

/* the following hold state information */
int first_bad_char; /* = '\0' */
sgj_opaque_p basep; /* base JSON object pointer */
Expand All @@ -97,12 +98,13 @@ typedef struct sgj_state_t {
* Note: strlen(in_name) should be <= max_sname_len . */
char * sgj_convert_to_snake_name(const char * in_name, char * sname,
int max_sname_len);

/* There are many variants of JSON supporting functions below and some
* abbreaviations are used to shorten their function names:
* abbreviations are used to shorten their function names:
* sgj_ - prefix of all the functions related to (non-)JSON output
* hr - human readable form (as it was before JSON)
* js - JSON only output (unless 'hr_js' given)
* hr_js - human readable and JSON output
* js - JSON only output
* haj - human readable and JSON output, hr goes in 'output' array
* pr - has printf() like variadic arguments
* _r - suffix indicating the return value should/must be used
* nv - adds a name-value JSON field (or several)
Expand All @@ -113,7 +115,7 @@ char * sgj_convert_to_snake_name(const char * in_name, char * sname,
* str - same as s
* hex - value is hexadecimal in a JSON string object
* _nex - extra 'name_extra' JSON string object about name
* new - object that needs sgj_free_unattached() it not attached
* new - object that needs sgj_free_unattached() if not attached
*
* */

Expand Down Expand Up @@ -225,7 +227,7 @@ sgj_opaque_p sgj_js_nv_b(sgj_state * jsp, sgj_opaque_p jop,
sgj_opaque_p sgj_js_nv_o(sgj_state * jsp, sgj_opaque_p jop,
const char * name, sgj_opaque_p ua_jop);

/* The '_hr_js_' refers to generating output both for human readable and/or
/* The '_haj_' refers to generating output both for human readable and/or
* JSON with a single invocation. If jsp is non-NULL and jsp->pr_out_hr is
* true then both JSON and human readable output is formed (and the latter is
* placed in the jsp->out_hrp JSON array). The human readable form will have
Expand All @@ -236,44 +238,43 @@ sgj_opaque_p sgj_js_nv_o(sgj_state * jsp, sgj_opaque_p jop,
* made from 'value' is added to the JSON array pointed to by 'jop'.
* Otherwise a 'name'-d JSON object whose value is a JSON string object made
* from 'value' is added at 'jop'. */
void sgj_hr_js_vs(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
const char * value);
void sgj_haj_vs(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
const char * value);

/* Similar to sgj_hr_js_vs()'s description with 'JSON string object'
/* Similar to sgj_haj_vs()'s description with 'JSON string object'
* replaced by 'JSON integer object'. */
void sgj_hr_js_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
int64_t value, bool hex_as_well);
void sgj_hr_js_vistr(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
int64_t value, bool hex_as_well, const char * val_s);
void sgj_haj_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
int64_t value, bool hex_as_well);
void sgj_haj_vistr(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
int64_t value, bool hex_as_well, const char * val_s);

/* The '_nex' refers to a "name_extra" (information) sub-object (a JSON
* string) which explains a bit more about the 'name' entry. This is useful
* when T10 specifies the name as an abbreviation (e.g. SYSV). Whether this
* sub-object is shown in the JSON output is controlled by the 'n' control
* character. */
void sgj_hr_js_vi_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
int64_t value, bool hex_as_well, const char * nex_s);
void sgj_hr_js_vistr_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
int64_t value, bool hex_as_well,
const char * val_s, const char * nex_s);

/* Similar to above '_hr_js_' calls but a named sub-object is always formed
void sgj_haj_vi_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
int64_t value, bool hex_as_well, const char * nex_s);
void sgj_haj_vistr_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
int64_t value, bool hex_as_well,
const char * val_s, const char * nex_s);

/* Similar to above '_haj_' calls but a named sub-object is always formed
* containing a JSON integer object named "i" whose value is 'value'. The
* returned pointer is to that sub-object. */
sgj_opaque_p sgj_hr_js_subo_r(sgj_state * jsp, sgj_opaque_p jop,
int leadin_sp, const char * name,
enum sgj_separator_t sep, int64_t value,
bool hex_as_well);
sgj_opaque_p sgj_haj_subo_r(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
int64_t value, bool hex_as_well);

/* Similar to sgj_hr_js_vs()'s description with 'JSON string object'
* replaced by 'JSON boolean object'. */
void sgj_hr_js_vb(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep, bool value);
/* Similar to sgj_haj_vs()'s description with 'JSON string object' replaced
* by 'JSON boolean object'. */
void sgj_haj_vb(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep, bool value);

/* This function only produces JSON output if jsp is non-NULL and
* jsp->pr_as_json is true. It adds a named object at 'jop' (or jop->basep
Expand Down Expand Up @@ -332,7 +333,7 @@ void sgj_js_str_out(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
* issue is detetected, else it returns true. */
* issue is detected, else it returns true. */
bool sgj_js_sense(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * sbp,
int sb_len);

Expand Down
1 change: 1 addition & 0 deletions lib/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ AM_CFLAGS = -Wall -W $(DBG_CFLAGS)
# AM_CFLAGS = -Wall -W -pedantic -std=c++14
# AM_CFLAGS = -Wall -W -pedantic -std=c++1z
# AM_CFLAGS = -Wall -W -pedantic -std=c++20
# AM_CFLAGS = -Wall -W -pedantic -std=c++23

lib_LTLIBRARIES = libsgutils2.la

Expand Down
1 change: 1 addition & 0 deletions lib/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ AM_CFLAGS = -Wall -W $(DBG_CFLAGS)
# AM_CFLAGS = -Wall -W -pedantic -std=c++14
# AM_CFLAGS = -Wall -W -pedantic -std=c++1z
# AM_CFLAGS = -Wall -W -pedantic -std=c++20
# AM_CFLAGS = -Wall -W -pedantic -std=c++23
lib_LTLIBRARIES = libsgutils2.la
libsgutils2_la_LDFLAGS = -version-info 2:0:0 -no-undefined -release ${PACKAGE_VERSION}
libsgutils2_la_LIBADD = @GETOPT_O_FILES@
Expand Down
8 changes: 4 additions & 4 deletions lib/sg_cmds_basic.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ sg_ll_inquiry_com(struct sg_pt_base * ptvp, int sg_fd, bool cmddt, bool evpd,
bool local_cdb = true;
int res, ret, sense_cat, resid;
uint8_t inq_cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
uint8_t * up;

if (resp == NULL) {
Expand Down Expand Up @@ -630,7 +630,7 @@ sg_ll_test_unit_ready_com(struct sg_pt_base * ptvp, int sg_fd, int pack_id,
bool local_cdb = true;
int res, ret, sense_cat;
uint8_t tur_cdb[TUR_CMDLEN] = {TUR_CMD, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;

if (verbose) {
char b[128];
Expand Down Expand Up @@ -741,7 +741,7 @@ sg_ll_request_sense_com(struct sg_pt_base * ptvp, int sg_fd, bool desc,
static const char * const rq_s = "request sense";
uint8_t rs_cdb[REQUEST_SENSE_CMDLEN] =
{REQUEST_SENSE_CMD, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;

if (desc)
rs_cdb[1] |= 0x1;
Expand Down Expand Up @@ -840,7 +840,7 @@ sg_ll_report_luns_com(struct sg_pt_base * ptvp, int sg_fd, int select_report,
int ret, res, sense_cat;
uint8_t rl_cdb[REPORT_LUNS_CMDLEN] =
{REPORT_LUNS_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;

rl_cdb[2] = select_report & 0xff;
sg_put_unaligned_be32((uint32_t)mx_resp_len, rl_cdb + 6);
Expand Down
22 changes: 11 additions & 11 deletions lib/sg_cmds_basic2.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ sg_ll_sync_cache_10(int sg_fd, bool sync_nv, bool immed, int group,
int res, ret, sense_cat;
uint8_t sc_cdb[SYNCHRONIZE_CACHE_CMDLEN] =
{SYNCHRONIZE_CACHE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
struct sg_pt_base * ptvp;

if (sync_nv)
Expand Down Expand Up @@ -154,7 +154,7 @@ sg_ll_readcap_16(int sg_fd, bool pmi, uint64_t llba, void * resp,
uint8_t rc_cdb[SERVICE_ACTION_IN_16_CMDLEN] =
{SERVICE_ACTION_IN_16_CMD, READ_CAPACITY_16_SA,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
struct sg_pt_base * ptvp;

if (pmi) { /* lbs only valid when pmi set */
Expand Down Expand Up @@ -209,7 +209,7 @@ sg_ll_readcap_10(int sg_fd, bool pmi, unsigned int lba, void * resp,
int ret, res, sense_cat;
uint8_t rc_cdb[READ_CAPACITY_10_CMDLEN] =
{READ_CAPACITY_10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
struct sg_pt_base * ptvp;

if (pmi) { /* lbs only valid when pmi set */
Expand Down Expand Up @@ -262,7 +262,7 @@ sg_ll_mode_sense6(int sg_fd, bool dbd, int pc, int pg_code, int sub_pg_code,
int res, ret, sense_cat, resid;
uint8_t modes_cdb[MODE_SENSE6_CMDLEN] =
{MODE_SENSE6_CMD, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
struct sg_pt_base * ptvp;

modes_cdb[1] = (uint8_t)(dbd ? 0x8 : 0);
Expand Down Expand Up @@ -361,7 +361,7 @@ sg_ll_mode_sense10_v2(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code,
struct sg_pt_base * ptvp;
uint8_t modes_cdb[MODE_SENSE10_CMDLEN] =
{MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;

modes_cdb[1] = (uint8_t)((dbd ? 0x8 : 0) | (llbaa ? 0x10 : 0));
modes_cdb[2] = (uint8_t)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
Expand Down Expand Up @@ -448,7 +448,7 @@ sg_ll_mode_select6_v2(int sg_fd, bool pf, bool rtd, bool sp, void * paramp,
int res, ret, sense_cat;
uint8_t modes_cdb[MODE_SELECT6_CMDLEN] =
{MODE_SELECT6_CMD, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
struct sg_pt_base * ptvp;

modes_cdb[1] = (uint8_t)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0));
Expand Down Expand Up @@ -519,7 +519,7 @@ sg_ll_mode_select10_v2(int sg_fd, bool pf, bool rtd, bool sp, void * paramp,
int res, ret, sense_cat;
uint8_t modes_cdb[MODE_SELECT10_CMDLEN] =
{MODE_SELECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
struct sg_pt_base * ptvp;

modes_cdb[1] = (uint8_t)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0));
Expand Down Expand Up @@ -818,7 +818,7 @@ sg_ll_log_sense_v2(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
int res, ret, sense_cat, resid;
uint8_t logs_cdb[LOG_SENSE_CMDLEN] =
{LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
struct sg_pt_base * ptvp;

if (mx_resp_len > 0xffff) {
Expand Down Expand Up @@ -902,7 +902,7 @@ sg_ll_log_select(int sg_fd, bool pcr, bool sp, int pc, int pg_code,
int res, ret, sense_cat;
uint8_t logs_cdb[LOG_SELECT_CMDLEN] =
{LOG_SELECT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
struct sg_pt_base * ptvp;

if (param_len > 0xffff) {
Expand Down Expand Up @@ -973,7 +973,7 @@ sg_ll_start_stop_unit_com(struct sg_pt_base * ptvp, int sg_fd, bool immed,
bool local_cdb = true;
int res, ret, sense_cat;
uint8_t ssuBlk[START_STOP_CMDLEN] = {START_STOP_CMD, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;

if (immed)
ssuBlk[1] = 0x1;
Expand Down Expand Up @@ -1073,7 +1073,7 @@ sg_ll_prevent_allow(int sg_fd, int prevent, bool noisy, int verbose)
int res, ret, sense_cat;
uint8_t p_cdb[PREVENT_ALLOW_CMDLEN] =
{PREVENT_ALLOW_CMD, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
struct sg_pt_base * ptvp;

if ((prevent < 0) || (prevent > 3)) {
Expand Down

0 comments on commit 048bd12

Please sign in to comment.