aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2022-06-25 04:05:14 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2022-06-25 04:05:14 +0000
commit2e225c87784735360e9619766efe06782179a86a (patch)
tree1df2832c733c55207261b829ec7f0146287afe82
parenta3eb530bb4b93949287f19a2b6fb418901f1f699 (diff)
downloadsg3_utils-2e225c87784735360e9619766efe06782179a86a.tar.gz
sg_rem_rest_elem: new utility for removing or restoring elements; bug fixes
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@955 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--COVERAGE4
-rw-r--r--ChangeLog6
-rw-r--r--README.details17
-rw-r--r--doc/README4
-rw-r--r--doc/sg3_utils.88
-rw-r--r--doc/sg_decode_sense.813
-rw-r--r--doc/sg_get_lba_status.820
-rw-r--r--doc/sg_rem_rest_elem.894
-rw-r--r--doc/sg_zone.817
-rw-r--r--include/sg_lib.h67
-rw-r--r--include/sg_pr2serr.h94
-rw-r--r--inhex/fixed_sense.hex5
-rw-r--r--inhex/vpd_di_all.hex23
-rw-r--r--lib/sg_lib.c151
-rw-r--r--lib/sg_lib_data.c4
-rw-r--r--lib/sg_pr2serr.c1060
-rw-r--r--lib/sg_pt_haiku.c2
-rwxr-xr-xscripts/rescan-scsi-bus.sh20
-rw-r--r--src/Makefile.am12
-rw-r--r--src/Makefile.in78
-rw-r--r--src/sg_decode_sense.c105
-rw-r--r--src/sg_format.c85
-rw-r--r--src/sg_get_elem_status.c33
-rw-r--r--src/sg_get_lba_status.c242
-rw-r--r--src/sg_opcodes.c81
-rw-r--r--src/sg_rem_rest_elem.c317
-rw-r--r--src/sg_rep_zones.c121
-rw-r--r--src/sg_requests.c17
-rw-r--r--src/sg_sanitize.c32
-rw-r--r--src/sg_unmap.c45
-rw-r--r--src/sg_vpd.c2
-rw-r--r--src/sg_vpd_vendor.c2
-rw-r--r--src/sg_zone.c64
-rw-r--r--testing/sg_mrq_dd.cpp4
-rw-r--r--testing/sg_tst_json_builder.c3
-rw-r--r--testing/sgh_dd.cpp4
36 files changed, 2258 insertions, 598 deletions
diff --git a/COVERAGE b/COVERAGE
index ab60a6c1..09c90105 100644
--- a/COVERAGE
+++ b/COVERAGE
@@ -72,6 +72,7 @@ RECEIVE COPY STATUS(LID1) sg_copy_results, ++
RECEIVE DIAGNOSTIC RESULTS sg_senddiag, sg_ses, sg_ses_microcode ++
RECEIVE ROD TOKEN INFORMATION ddpt, ddptctl ++
REMOVE ELEMENT AND MODIFY ZONES sg_zone
+REMOVE ELEMENT AND TRUNCATE sg_rem_rest_elem
REPORT ALL ROD TOKENS ddptctl ++
REPORT DENSITY SUPPORT sg_rep_density
REPORT IDENTIFYING INFORMATION sg_ident, ++ (2)
@@ -87,6 +88,7 @@ REPORT ZONES sg_rep_zones
REPORT ZONE DOMAINS sg_rep_zones
REQUEST SENSE sg_requests, ++
RESET WRITE POINTER sg_reset_wp
+RESTORE ELEMENTS AND REBUILD sg_rem_rest_elem
SANITIZE sg_sanitize
SEEK(10) sg_seek ++
SEND DIAGNOSTIC sg_senddiag, sg_ses, sg_ses_microcode ++
@@ -183,4 +185,4 @@ THIRD PARTY COPY IN (0x83).
Douglas Gilbert
-21st January 2022
+10 June 2022
diff --git a/ChangeLog b/ChangeLog
index bb1ddfd7..75f8d6e9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,12 +2,14 @@ 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 [20220602] [svn: r954]
+Changelog for pre-release sg3_utils-1.48 [20220625] [svn: r955]
- some utilities: add experimental --json[=JO] option
- sg_z_act_query: new utility for sending either a
Zone activate or Zone query command
- sg_rep_density: new utility for decoding the response of
Report density support command [ssc (tape)]
+ - sg_rem_rest_elem: new utility for removing or restoring
+ elements
- sg_rtpg: https://github.com/hreinecke/sg3_utils/pull/79
applied
- rescan-scsi-bus.sh: with '-r' it crashed due to change in
@@ -19,6 +21,7 @@ Changelog for pre-release sg3_utils-1.48 [20220602] [svn: r954]
numeric to alphabetical, change it back to numeric
- https://github.com/doug-gilbert/sg3_utils/pull/17
applied with tweaks: add timeout parameter
+ - clean $norm handling
- sg_rep_zones: add Report zone starting LBA granularity
field in REPORT ZONES response [zbc2r12]
- add --brief option, show part of header and last
@@ -44,6 +47,7 @@ Changelog for pre-release sg3_utils-1.48 [20220602] [svn: r954]
- sg_inq, sg_vpd: Device Identication VPD page, change
"IEEE Company_id" to "AOI" as per spc6r06.pdf
- add support for Hitachi/HP open-v ldev names
+ - sg_vpd: apply github pull 18 (missing LF)
- sg_opcodes: cleanup error reporting
- add --inhex=FN to process earlier -HHH
- sg_format: allow disk formats on ZBC (zoned) disks
diff --git a/README.details b/README.details
index ea976e79..47fc2e27 100644
--- a/README.details
+++ b/README.details
@@ -263,13 +263,14 @@ subdirectory of the sg3_utils package:
sg_luns, sg_map, sg_map26, sg_modes, sg_opcodes, sg_persist, sg_prevent,
sg_raw, sg_rbuf, sg_rdac, sg_read, sg_read_attr, sg_readcap,
sg_read_block_limits, sg_read_buffer, sg_read_long, sg_reassign,
- sg_referrals, sg_rep_pip, sg_rep_zones, sg_request, sg_reset, sg_rmsn,
- sg_rtpg, sg_safte, sg_sanitize, sg_sat_identify, sg_sat_phy_event,
- sg_sat_read_gplog, sg_sat_set_features, sg_scan, sg_seek, sg_senddiag,
- sg_ses, sg_ses_microcode, sg_start, sg_stpg, sg_stream_ctl, sg_sync,
- sg_test_rwbuff, sg_timestamp, sg_turs, sg_unmap, sg_verify, sg_vpd,
- sg_write_buffer, sg_write_long, sg_write_same, sg_write_verify,
- sg_write_x, sg_wr_mode, sg_xcopy, sg_zone, sg_z_act_query
+ sg_referrals, sg_rem_rest_elem, sg_rep_density, sg_rep_pip, sg_rep_zones,
+ sg_request, sg_reset, sg_rmsn, sg_rtpg, sg_safte, sg_sanitize,
+ sg_sat_identify, sg_sat_phy_event, sg_sat_read_gplog, sg_sat_set_features,
+ sg_scan, sg_seek, sg_senddiag, sg_ses, sg_ses_microcode, sg_start,
+ sg_stpg, sg_stream_ctl, sg_sync, sg_test_rwbuff, sg_timestamp, sg_turs,
+ sg_unmap, sg_verify, sg_vpd, sg_write_buffer, sg_write_long,
+ sg_write_same, sg_write_verify, sg_write_x, sg_wr_mode, sg_xcopy, sg_zone,
+ sg_z_act_query
Each of the above utilities depends on header files found in the 'include'
subdirectory and library code found in the 'lib' subdirectory. Associated
@@ -541,4 +542,4 @@ See https://sg.danny.cz/sg/tools.html
Douglas Gilbert dgilbert@interlog.com
-18th November 2021
+10th June 2022
diff --git a/doc/README b/doc/README
index d20d510f..6664a32b 100644
--- a/doc/README
+++ b/doc/README
@@ -23,6 +23,8 @@ https://sg.danny.cz/sg/sg_io.html
https://sg.danny.cz/sg/tools.html
- overview of around 25 storage and SCSI tools
+Many of those pages are also found at: https://doug-gilbert.github.io/
+
There are two versions of sg_scan: one for Linux and the other for Windows.
They have different man pages: sg_scan.8.linux and sg_scan.8.win32 with
@@ -31,4 +33,4 @@ sg_scan.8 . sg_scan is not supported for other ports.
Douglas Gilbert
-16th April 2021
+10th June 2022
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index fc0b70a0..5f4c8456 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -739,10 +739,10 @@ be given as "0x100" or "100h".
.SH FORMAT OF FILES CONTAINING ASCII HEX
Such a file is assumed to contain a sequence of one or two digit ASCII
hexadecimal values separated by whitespace. "Whitespace consists of either
-spaces, tabs, blank lines, or any combination thereof". Each one or two digit
-ASCII hex pair is decoded into a byte (i.e. 8 bits). The following will be
-decoded to valid (ascending valued)
-bytes: '0', '01', '3', 'c', 'F', '4a', 'cC', 'ff'.
+spaces, tabs, blank lines, or any combination thereof". Hyphens (e.g. '\-')
+are also allowed as separators. Each one or two digit ASCII hex pair is
+decoded into a byte (i.e. 8 bits). The following will be decoded to
+valid (ascending valued) bytes: '0', '01', '3', 'c', 'F', '4a', 'cC', 'ff'.
Lines containing only whitespace are ignored. The contents of any line
containing a hash mark ('#') is ignored from that point until the end of that
line. Users are encouraged to use hash marks to introduce comments in hex
diff --git a/doc/sg_decode_sense.8 b/doc/sg_decode_sense.8
index 7c952ed0..5680a075 100644
--- a/doc/sg_decode_sense.8
+++ b/doc/sg_decode_sense.8
@@ -65,10 +65,10 @@ feed. All other command line options and arguments are ignored.
\fB\-f\fR, \fB\-\-file\fR=\fIHFN\fR
the sense data is read in ASCII hexadecimal from a file called \fIHFN\fR.
The sense data should appear as a sequence of bytes separated by space,
-comma, tab or newline. Everything from and including a hash symbol to the
-end of that line is ignored. If \fI\-\-nospace\fR is set then no separator
-is required between the ASCII hexadecimal digits in \fIHFN\fR with bytes
-decoded from pairs of ASCII hexadecimal digits.
+comma, tab, hyphen or newline. Everything from and including a hash symbol
+to the end of that line is ignored. If \fI\-\-nospace\fR is set then no
+separator is required between the ASCII hexadecimal digits in \fIHFN\fR
+with bytes decoded from pairs of ASCII hexadecimal digits.
.TP
\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
@@ -82,6 +82,11 @@ starting with "0x3b,0x07,0x00,0xff").
In other cases (i.e. when \fI\-\-write=WFN\fR is not given, or this option
is given more than once) then the output is as described in the sg3_utils(8)
manpage.
+.br
+The combination of \fI\-\-inhex=HFN\fR and this option used three times
+can be useful to converting hexadecimal bytes (e.g. hyphen separated) into
+a more regular form. The short option form is more convenient for invoking
+this option three times (e.g. '\-HHH').
.TP
\fB\-i\fR, \fB\-\-inhex\fR=\fIHFN\fR
same action as \fI\-\-file=HFN\fR. This option was added for compatibility
diff --git a/doc/sg_get_lba_status.8 b/doc/sg_get_lba_status.8
index 282b3fed..b9fe7c18 100644
--- a/doc/sg_get_lba_status.8
+++ b/doc/sg_get_lba_status.8
@@ -1,10 +1,11 @@
-.TH SG_GET_LBA_STATUS "8" "August 2019" "sg3_utils\-1.45" SG3_UTILS
+.TH SG_GET_LBA_STATUS "8" "June 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg_get_lba_status \- send SCSI GET LBA STATUS(16 or 32) command
.SH SYNOPSIS
.B sg_get_lba_status
-[\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-brief\fR] [\fI\-\-element-id=EI\fR]
-[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-lba=LBA\fR]
+[\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-blockhex\fR] [\fI\-\-brief\fR]
+[\fI\-\-element-id=EI\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR]
+[\fI\-\-inhex=FN\fR] [\fI\-\-json[=JO\fR]] [\fI\-\-lba=LBA\fR]
[\fI\-\-maxlen=LEN\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR]
[\fI\-\-report\-type=RT\fR] [\fI\-\-scan-len=SL\fR] [\fI\-\-verbose\fR]
[\fI\-\-version\fR] \fIDEVICE\fR
@@ -56,6 +57,13 @@ option is not given) is output to stdout. A check is made that the given
it should according to SBC\-3 revision 20) and warnings are sent to stderr
if it doesn't.
.TP
+\fB\-B\fR, \fB\-\-blockhex\fR
+the number of blocks in each LBA status descriptor is usually displayed in
+decimal. An exception is when the \fI\-\-brief\fR option is given in which
+case it is shown in hexadecimal. When the option is given once, both cases
+are output in hexadecimal. When the option is given twice, both cases are
+output in decimal.
+.TP
\fB\-e\fR, \fB\-\-element\-id\fR=\fIEI\fR
where \fIEI\fR is the element identifier of the physical element for which
the LBAs shall be reported based on the value in the report type field (i.e.
@@ -78,6 +86,10 @@ in the sg3_utils manpage for more information. If \fIDEVICE\fR is also
given then it is ignored. If the \fI\-\-raw\fR option is also given then
the contents of \fIFN\fR are treated as binary.
.TP
+\fB\-j\fR, \fB\-\-json[\fR=\fIJO\fR]
+output is in JSON format instead of human readable form. This is an
+EXPERIMENTAL feature; more information to follow.
+.TP
\fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR
where \fILBA\fR is the starting Logical Block Address (LBA) to check the
provisioning status for. Note that the \fIDEVICE\fR chooses how many
@@ -141,7 +153,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2009\-2019 Douglas Gilbert
+Copyright \(co 2009\-2022 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/sg_rem_rest_elem.8 b/doc/sg_rem_rest_elem.8
new file mode 100644
index 00000000..6300eef7
--- /dev/null
+++ b/doc/sg_rem_rest_elem.8
@@ -0,0 +1,94 @@
+.TH SG_REM_REST_ELEM "8" "June 2022" "sg3_utils\-1.48" SG3_UTILS
+.SH NAME
+sg_rem_rest_elem \- send SCSI remove or restore element command
+.SH SYNOPSIS
+.B sg_rem_rest_elem
+[\fI\-\-capacity=RC\fR] [\fI\-\-element=EID\fR] [\fI\-\-help\fR]
+[\fI\-\-quick\fR] [\fI\-\-remove\fR] [\fI\-\-restore\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] \fIDEVICE\fR
+.SH DESCRIPTION
+.\" Add any additional description here
+.PP
+Sends a SCSI REMOVE ELEMENT AND TRUNCATE [RMEAT] or RESTORE ELEMENTS AND
+REBUILD [RSEAB] command to the \fIDEVICE\fR. Since both these commands have
+a potentially huge impact on the \fIDEVICE\fR (similar to the FORMAT UNIT
+command: destroying data and taking a long time to complete fully),
+neither is executed by default.
+.PP
+Unlike the FORMAT UNIT command, these commands seem designed to work in
+the background. So they will return quickly (although sbc5r01.pdf does not
+state that) and the disk will be placed in a reduced functionality state
+where only a specified number of commands will be executed (e.g. INQUIRY and
+REPORT LUNS) until the operation is complete. Other commands will receive
+sense data with a sense key of NOT READY and an additional sense code
+of 'Depopulation in progress' (for RMEAT) or 'Depopulation restoration in
+progress' (for RSEAB).
+.PP
+The REMOVE ELEMENT AND TRUNCATE has a close relative in ZBC\-2 called the
+REMOVE ELEMENT AND MODIFY ZONES [RMEMZ] command. See the sg_zone utility
+for an implementation of the latter command.
+.br
+The difference between RMEAT and RMEMZ is that the former "changes the
+association between LBAs and physical blocks" and the latter does not
+change that association. Zones affected by the RMEMZ command are placed
+into the zone condition: "Offline".
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
+.TP
+\fB\-c\fR, \fB\-\-capacity\fR=\fIRC\fR
+RC stands for Requested Capacity and is the number of logical blocks the
+\fIDEVICE\fR should have after the element is removed with the RMEAT
+command. The default value is 0 which allows the \fIDEVICE\fR to decide
+what the reduced capacity will be after the element removal. The RSEAB
+command ignores this value.
+.TP
+\fB\-e\fR, \fB\-\-element\fR=\fIEID\fR
+where \fIEID\fR is an element identifier which is a 32 bit unsigned integer
+starting at one. This field is used by the RMEAT command and ignored
+otherwise. The default value is zero (which is invalid). So the user needs
+to supply a valid element identifier when \fI\-\-remove\fR is used.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+output the usage message then exit.
+.TP
+\fB\-q\fR, \fB\-\-quick\fR
+the default action (i.e. when this option is not given) is to give the user
+15 seconds to reconsider doing a remove or restore element operation on the
+\fIDEVICE\fR. When this option is given that step (i.e. the 15 second
+warning period) is bypassed.
+.TP
+\fB\-r\fR, \fB\-\-remove\fR
+causes the REMOVE ELEMENT AND TRUNCATE command to be sent to the
+\fIDEVICE\fR. In practice, \fI\-\-element=EID\fR needs to be also given.
+.TP
+\fB\-R\fR, \fB\-\-restore\fR
+causes the RESTORE ELEMENTS AND REBUILD command to be sent to the
+\fIDEVICE\fR.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+increase the level of verbosity, (i.e. debug output).
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+print the version string and then exit.
+.SH NOTES
+Once an element is removed successfully it is termed as "depopulated".
+Depopulated elements that have the 'Restoration Allowed' (RALWD) bit
+set (see sg_get_elem_status) are candidates for future restoration.
+.PP
+A (storage) element of a rotating hard disk is once side of a platter
+typically associated with one head. Such hard disks typically have multiple
+platters with two heads per platter (i.e. one head each side of the platter).
+.SH EXIT STATUS
+The exit status of sg_rem_rest_elem is 0 when it is successful. Otherwise see
+the sg3_utils(8) man page.
+.SH AUTHORS
+Written by Douglas Gilbert.
+.SH "REPORTING BUGS"
+Report bugs to <dgilbert at interlog dot com>.
+.SH COPYRIGHT
+Copyright \(co 2022 Douglas Gilbert
+.br
+This software is distributed under a FreeBSD license. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+.SH "SEE ALSO"
+.B sg_get_elem_status,sg_zone(sg3_utils)
diff --git a/doc/sg_zone.8 b/doc/sg_zone.8
index 53cf7cfe..6c39dea2 100644
--- a/doc/sg_zone.8
+++ b/doc/sg_zone.8
@@ -1,4 +1,4 @@
-.TH SG_ZONE "8" "December 2021" "sg3_utils\-1.48" SG3_UTILS
+.TH SG_ZONE "8" "June 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg_zone \- send a SCSI ZONE modifying command
.SH SYNOPSIS
@@ -70,6 +70,17 @@ where \fIID\fR is placed in the cdb's ZONE ID field. A zone id is a zone
start logical block address (LBA). The default value is 0. \fIID\fR is
assumed to be in decimal unless prefixed with '0x' or has a trailing 'h'
which indicate hexadecimal.
+.SH NOTES
+After a REMOVE ELEMENT AND MODIFY ZONES command has completed, the element
+in question is said to be depopulated and any affected zones are placed in
+the 'offline' zone condition.
+.PP
+SBC\-4 has a similar command to REMOVE ELEMENT AND MODIFY ZONES called REMOVE
+ELEMENT AND TRUNCATE. The difference is that the latter "changes the
+association between LBAs and physical blocks" and the former does not change
+that association. In both cases, depopulated elements that have
+the 'Restoration Allowed' (RALWD) bit set (see sg_get_elem_status) may be
+restored with the RESTORE ELEMENTS AND REBUILD command (see sg_rem_rest_elem).
.SH EXIT STATUS
The exit status of sg_zone is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
@@ -78,9 +89,9 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2014\-2021 Douglas Gilbert
+Copyright \(co 2014\-2022 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-.B sg_rep_zones,sg_reset_wp,sg_z_act_query(sg3_utils)
+.B sg_rem_rest_elem,sg_rep_zones,sg_reset_wp,sg_z_act_query(sg3_utils)
diff --git a/include/sg_lib.h b/include/sg_lib.h
index 383e9072..0fa4693a 100644
--- a/include/sg_lib.h
+++ b/include/sg_lib.h
@@ -230,9 +230,16 @@ int sg_get_sense_key(const uint8_t * sensep, int sense_len);
/* Yield string associated with sense_key value. Returns 'buff'. */
char * sg_get_sense_key_str(int sense_key, int buff_len, char * buff);
-/* Yield string associated with ASC/ASCQ values. Returns 'buff'. */
+/* Yield string associated with ASC/ASCQ values. Returns 'buff'. Prefixes
+ * any valid additional sense found with "Additional sense: ". */
char * sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff);
+/* Same as sg_get_asc_ascq_str() when add_sense_leadin is true. When it is
+ * false this function does _not_ prefix any valid additional sense found
+ * with "Additional sense: ". */
+char * sg_get_additional_sense_str(int asc, int ascq, bool add_sense_leadin,
+ int buff_len, char * buff);
+
/* Returns true if valid bit set, false if valid bit clear. Irrespective the
* information field is written out via 'info_outp' (except when it is
* NULL). Handles both fixed and descriptor sense formats. */
@@ -584,6 +591,25 @@ int sg_vpd_dev_id_iter(const uint8_t * initial_desig_desc, int page_len,
* If errnum is negative, flip its sign. */
char * safe_strerror(int errnum);
+/* Not all platforms support the Unix sleep(seconds) function. */
+void sg_sleep_secs(int num_secs);
+
+/* There are several SCSI commands that are very destructive for the user
+ * data stored on a device. The FORMAT UNIT command is the prime example
+ * but there are an increasing number of newer SCSI commands that remove or
+ * destroy some or all of the user's data. This function takes 15 seconds,
+ * divided into three parts, saying that 'cmd_name' will be executed on
+ * 'dev_name' and then waits for 5 seconds inviting the user to press
+ * control-C to abort the operation. After three such prompts the function
+ * returns and the utility start to execute the "dangerous" SCSI command,
+ * Utilities that use this function usually have a --quick option to bypass
+ * this call. That may be appropriate if the utility in question is called
+ * from a script or in background processing. If 'stress_all' is true then
+ * state "ALL data" will be lost, if false drop the "ALL". */
+void
+sg_warn_and_wait(const char * cmd_name, const char * dev_name,
+ bool stress_all);
+
/* Print (to stdout) 'str' of bytes in hex, 16 bytes per line optionally
* followed at the right hand side of the line with an ASCII interpretation.
@@ -607,24 +633,24 @@ void dStrHexErr(const char * str, int len, int no_ascii);
* '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);
-/* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space
- * separated) to 'b' not to exceed 'b_len' characters. Each line
- * starts with 'leadin' (NULL for no leadin) and there are 16 bytes
- * per line with an extra space between the 8th and 9th bytes. 'format'
- * is 0 for repeat in printable ASCII ('.' for non printable chars) to
- * right of each line; 1 don't (so just output ASCII hex). Note that
- * an address is not printed on each line preceding the hex data. Returns
- * number of bytes written to 'b' excluding the trailing '\0'.
- * The only difference between dStrHexStr() and hex2str() is the type of
- * the first argument. */
-int dStrHexStr(const char * str, int len, const char * leadin, int format,
+/* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space separated)
+ * to 'b' not to exceed 'b_len' characters. Each line starts with 'leadin'
+ * (NULL for no leadin) and there are 16 bytes per line with an extra space
+ * between the 8th and 9th bytes. 'oformat' is 0 for repeat in printable ASCII
+ * ('.' for non printable chars) to right of each line; 1 don't (so just
+ * output ASCII hex). If 'oformat' is 2 output same as 1 but any LFs are
+ * replaced by space (and trailing spaces are trimmed). Note that an address
+ * is not printed on each line preceding the hex data. Returns number of bytes
+ * written to 'b' excluding the trailing '\0'. The only difference between
+ * dStrHexStr() and hex2str() is the type of the first argument. */
+int dStrHexStr(const char * str, int len, const char * leadin, int oformat,
int cb_len, char * cbp);
-int hex2str(const uint8_t * b_str, int len, const char * leadin, int format,
+int hex2str(const uint8_t * b_str, int len, const char * leadin, int oformat,
int cb_len, char * cbp);
/* Similar to hex2str() but outputs to file pointed to be fp */
-void hex2fp(const uint8_t * b_str, int len, const char * leadin, int format,
- FILE * fp);
+void hex2fp(const uint8_t * b_str, int len, const char * leadin, int oformat,
+ FILE * fp);
/* The following 2 functions are equivalent to dStrHex() and dStrHexErr()
* respectively. The difference is only the type of the first of argument:
@@ -635,11 +661,12 @@ void hex2stderr(const uint8_t * b_str, int len, int no_ascii);
/* Read ASCII hex bytes or binary from fname (a file named '-' taken as
* stdin). If reading ASCII hex then there should be either one entry per
- * line or a comma, space or tab separated list of bytes. If no_space is
- * set then a string of ACSII hex digits is expected, 2 per byte. Everything
- * from and including a '#' on a line is ignored. Returns 0 if ok, or an
- * error code. If the error code is SG_LIB_LBA_OUT_OF_RANGE then mp_arr
- * would be exceeded and both mp_arr and mp_arr_len are written to. */
+ * line or a comma, space, hyphen or tab separated list of bytes. If
+ * no_space is * set then a string of ACSII hex digits is expected, 2 per
+ * byte. Everything from and including a '#' on a line is ignored. Returns
+ * 0 if ok, or an error code. If the error code is
+ * SG_LIB_LBA_OUT_OF_RANGE then mp_arr would be exceeded and both mp_arr
+ * and mp_arr_len are written to. */
int sg_f2hex_arr(const char * fname, bool as_binary, bool no_space,
uint8_t * mp_arr, int * mp_arr_len, int max_arr_len);
diff --git a/include/sg_pr2serr.h b/include/sg_pr2serr.h
index a7a09f86..9a1fd273 100644
--- a/include/sg_pr2serr.h
+++ b/include/sg_pr2serr.h
@@ -69,6 +69,7 @@ typedef struct sgj_state_t {
/* the following set by default, the SG3_UTILS_JSON_OPTS envirinment
* variable or command line argument to --json option, in that order. */
bool pr_as_json; /* = false */
+ bool pr_ane; /* 'a' abbreviated name expansion (def: false) */
bool pr_exit_status; /* 'e' (def: true) */
bool pr_hex; /* 'h' (def: false) */
bool pr_leadin; /* 'l' (def: true) */
@@ -121,7 +122,7 @@ sgj_opaque_p sgj_start(const char * util_name, const char * ver_str,
* object or array. If jsp is NULL or jsp->pr_as_json is false nothing happens
* and NULL is returned. Note that this JSON object is _not_ placed in the
* in-core tree controlled by jsp (jsp->basep); it may be added later as the
- * third argument to sgj_add_array_element(), for example. */
+ * fourth argument to sgj_add_nv_o(), for example. */
sgj_opaque_p sgj_new_unattached_object(sgj_state * jsp);
sgj_opaque_p sgj_new_unattached_array(sgj_state * jsp);
@@ -150,8 +151,8 @@ sgj_opaque_p sgj_new_named_array(sgj_state * jsp, sgj_opaque_p jop,
* 'value'. If 'name' is NULL then 'jop' is assumed to be a JSON array and
* a JSON string formed from 'value' is added. If successful returns a
* a pointer newly formed JSON string. */
-sgj_opaque_p sgj_add_val_s(sgj_state * jsp, sgj_opaque_p jop,
- const char * name, const char * value);
+sgj_opaque_p sgj_add_nv_s(sgj_state * jsp, sgj_opaque_p jop,
+ const char * name, const char * value);
/* 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
@@ -160,8 +161,8 @@ sgj_opaque_p sgj_add_val_s(sgj_state * jsp, sgj_opaque_p jop,
* 'value'. If 'name' is NULL then 'jop' is assumed to be a JSON array and
* a JSON integer formed from 'value' is added. If successful returns a
* a pointer newly formed JSON integer. */
-sgj_opaque_p sgj_add_val_i(sgj_state * jsp, sgj_opaque_p jop,
- const char * name, int64_t value);
+sgj_opaque_p sgj_add_nv_i(sgj_state * jsp, sgj_opaque_p jop,
+ const char * name, int64_t value);
/* 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
@@ -170,8 +171,8 @@ sgj_opaque_p sgj_add_val_i(sgj_state * jsp, sgj_opaque_p jop,
* 'value'. If 'name' is NULL then 'jop' is assumed to be a JSON array and
* a JSON boolean formed from 'value' is added. If successful returns a
* a pointer newly formed JSON boolean. */
-sgj_opaque_p sgj_add_val_b(sgj_state * jsp, sgj_opaque_p jop,
- const char * name, bool value);
+sgj_opaque_p sgj_add_nv_b(sgj_state * jsp, sgj_opaque_p jop,
+ const char * name, bool value);
/* If jsp is NULL, jsp->pr_as_json is false or ua_jop is NULL nothing then
* happens and NULL is returned. 'jop' is the insertion point but if it is
@@ -179,13 +180,13 @@ sgj_opaque_p sgj_add_val_b(sgj_state * jsp, sgj_opaque_p jop,
* object is added using 'name' and the associated value is ua_jop. If 'name'
* is NULL then 'jop' is assumed to be a JSON array and ua_jop is added to
* it. If successful returns ua_jop . The "ua_" prefix stands for unattached.
- * Tha should be the case before invocation and it will be attached to jop
+ * That should be the case before invocation and it will be attached to jop
* after a successful invocation. This means that ua_jop must have been
* created by sgj_new_unattached_object() or similar. */
-sgj_opaque_p sgj_add_val_o(sgj_state * jsp, sgj_opaque_p jop,
- const char * name, sgj_opaque_p ua_jop);
+sgj_opaque_p sgj_add_nv_o(sgj_state * jsp, sgj_opaque_p jop,
+ const char * name, sgj_opaque_p ua_jop);
-/* The '_twin_' refers to generating output both for human readable and/or
+/* The '_hr_js_' refers to generating output both for human readable and/or
* JSON with a single invocation. If jsp is non_NULL and jsp->pr_output is
* true then both JSON and human readable output is formed (and the latter is
* placed in the jsp->outputp JSON array). The human readable form will have
@@ -196,41 +197,74 @@ sgj_opaque_p sgj_add_val_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_pr_twin_vs(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep,
- const char * value);
+void sgj_pr_hr_js_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_pr_twin_vs()'s description with 'JSON string object'
+/* Similar to sgj_pr_hr_js_vs()'s description with 'JSON string object'
* replaced by 'JSON integer object'. */
-void sgj_pr_twin_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep,
- int64_t value);
+void sgj_pr_hr_js_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep,
+ int64_t value);
-/* Similar to sgj_pr_twin_vs()'s description with 'JSON string object'
+/* Similar to sgj_pr_hr_js_vs()'s description with 'JSON string object'
* replaced by 'JSON boolean object'. */
-void sgj_pr_twin_vb(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep, bool value);
+void sgj_pr_hr_js_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
* if jop is NULL) along with a value. If jsp->pr_hex is true then that
* value is two sub-objects, one named 'i' with a 'value' as a JSON integer,
* the other one named 'hex' with 'value' rendered as hex in a JSON string.
- * If jsp->pr_hex is false the there are no sub-objects and the 'value' is
+ * If jsp->pr_hex is false then there are no sub-objects and the 'value' is
* rendered as JSON integer. */
-void sgj_add_name_pair_ihex(sgj_state * jsp, sgj_opaque_p jop,
- const char * name, uint64_t value);
+void sgj_add_nv_ihex(sgj_state * jsp, sgj_opaque_p jop,
+ const char * name, uint64_t 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
* if jop is NULL) along with a value. If jsp->pr_string is true then that
* value is two sub-objects, one named 'i' with a 'val_i' as a JSON integer,
- * the other one named str_name with val_s rendered as a JSON string.
- * If jsp->pr_string is false the there are no sub-objects and the 'val_i' is
- * rendered as JSON integer. */
-void sgj_add_name_pair_istr(sgj_state * jsp, sgj_opaque_p jop,
- const char * name, int64_t val_i,
- const char * str_name, const char * val_s);
+ * the other one named str_name with val_s rendered as a JSON string. If
+ * str_name is NULL then "meaning" will be used. If jsp->pr_string is false
+ * then there are no sub-objects and the 'val_i' is rendered as a JSON
+ * integer. */
+void sgj_add_nv_istr(sgj_state * jsp, sgj_opaque_p jop,
+ const char * name, int64_t val_i,
+ const char * str_name, const char * val_s);
+
+void sgj_add_nv_ihexstr(sgj_state * jsp, sgj_opaque_p jop,
+ const char * name, int64_t val_i,
+ const char * str_name, const char * val_s);
+
+/* 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
+ * if jop is NULL) along with a value. If jsp->pr_ane is true then that
+ * value is two sub-objects, one named 'i' with a 'val_i' as a JSON integer,
+ * the other one named "abbreviated_name_expansion" with value ane_s rendered
+ * as a JSON string. If jsp->pr_hex and 'want_hex' are true, then a
+ * sub-object named 'hex' with a value rendered as a hex string equal to
+ * val_i. If jsp->pr_ane is false and either jsp->pr_hex or want_hex are
+ * false then there are no sub-objects and the 'val_i' is rendered as a JSON
+ * integer. */
+void sgj_add_nv_ihex_ane(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ int64_t val_i, bool want_hex, const char * ane_s);
+
+void sgj_add_nv_ihexstr_ane(sgj_state * jsp, sgj_opaque_p jop,
+ const char * name, int64_t val_i, bool want_hex,
+ const char * str_name, const char * val_s,
+ const char * ane_s);
+
+/* 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. */
+bool sgj_get_sense(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * sbp,
+ int sb_len);
+
+bool sgj_get_designation_descriptor(sgj_state * jsp, sgj_opaque_p jop,
+ const uint8_t * ddp, int dd_len);
/* Nothing in the in-core JSON tree is actually printed to 'fp' (typically
* stdout) until this call is made. If jsp is NULL, jsp->pr_as_json is false
diff --git a/inhex/fixed_sense.hex b/inhex/fixed_sense.hex
new file mode 100644
index 00000000..1c6464b4
--- /dev/null
+++ b/inhex/fixed_sense.hex
@@ -0,0 +1,5 @@
+# Test fixed format sense data. Values are in hex.
+# Invocation: 'sg_decode_sense -f fixed_sense.hex' [dpg 20220622]
+
+f0 00 03 00 00 12 34 0a 00 00 00 00 11 00 77 80
+01 98
diff --git a/inhex/vpd_di_all.hex b/inhex/vpd_di_all.hex
new file mode 100644
index 00000000..bc89c0b1
--- /dev/null
+++ b/inhex/vpd_di_all.hex
@@ -0,0 +1,23 @@
+#
+# An example invocation:
+# sg_vpd --inhex=vpd_di_all.hex
+
+00 83 00 82
+
+# Vendor specific designator
+01 00 00 16 11 22 33 44 55 66 77 88 99 aa bb cc
+dd ee ff ed cb a9 87 65 43 21
+
+# T10 vendor ID
+02 01 00 14
+41 42 43 20 20 20 20 20
+58 59 5a 31 32 33 34 35 36 37 38 39
+
+# EUI-64
+01 02 00 08 11 22 33 44 55 66 77 88
+01 02 00 0c 11 22 33 44 55 66 77 88 00 00 01 23
+01 02 00 10 01 23 45 67 89 ab cd ef 11 22 33 44 55 66 77 88
+
+# 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
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index 8922d323..418638b5 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -325,7 +325,8 @@ sg_get_sense_key_str(int sense_key, int buff_len, char * buff)
/* Yield string associated with ASC/ASCQ values. Returns 'buff'. */
char *
-sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
+sg_get_additional_sense_str(int asc, int ascq, bool add_sense_leadin,
+ int buff_len, char * buff)
{
int k, num, rlen;
bool found = false;
@@ -341,7 +342,10 @@ sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
(ascq >= ei2p->ascq_min) &&
(ascq <= ei2p->ascq_max)) {
found = true;
- num = sg_scnpr(buff, buff_len, "Additional sense: ");
+ if (add_sense_leadin)
+ num = sg_scnpr(buff, buff_len, "Additional sense: ");
+ else
+ num = 0;
rlen = buff_len - num;
sg_scnpr(buff + num, ((rlen > 0) ? rlen : 0), ei2p->text, ascq);
}
@@ -355,7 +359,10 @@ sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
if (eip->asc == asc &&
eip->ascq == ascq) {
found = true;
- sg_scnpr(buff, buff_len, "Additional sense: %s", eip->text);
+ if (add_sense_leadin)
+ sg_scnpr(buff, buff_len, "Additional sense: %s", eip->text);
+ else
+ sg_scnpr(buff, buff_len, "%s", eip->text);
}
}
if (! found) {
@@ -371,6 +378,13 @@ sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
return buff;
}
+/* Yield string associated with ASC/ASCQ values. Returns 'buff'. */
+char *
+sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
+{
+ return sg_get_additional_sense_str(asc, ascq, true, buff_len, buff);
+}
+
/* Attempt to find the first SCSI sense data descriptor that matches the
* given 'desc_type'. If found return pointer to start of sense data
* descriptor; otherwise (including fixed format sense data) returns NULL. */
@@ -829,7 +843,7 @@ sg_get_desig_assoc_str(int val)
static const char * desig_type_str_arr[] =
{
- "vendor specific [0x0]",
+ "Vendor specific [0x0]",
"T10 vendor identification",
"EUI-64 based",
"NAA",
@@ -979,7 +993,6 @@ sg_get_designation_descriptor_str(const char * lip, const uint8_t * ddp,
if (piv && ((1 == assoc) || (2 == assoc)))
n += sg_scnpr(b + n, blen - n, "%s transport: %s\n", lip,
sg_get_trans_proto_str(p_id, sizeof(e), e));
- /* printf(" associated with the %s\n", sdparm_assoc_arr[assoc]); */
switch (desig_type) {
case 0: /* vendor specific */
k = 0;
@@ -1049,7 +1062,7 @@ sg_get_designation_descriptor_str(const char * lip, const uint8_t * ddp,
}
ccc_id = sg_get_unaligned_be64(ip + ci_off);
n += sg_scnpr(b + n, blen - n, "%s IEEE identifier: 0x%"
- PRIx64 "x\n", lip, ccc_id);
+ PRIx64 "\n", lip, ccc_id);
if (12 == dlen) {
d_id = sg_get_unaligned_be32(ip + 8);
n += sg_scnpr(b + n, blen - n, "%s Directory ID: 0x%x\n",
@@ -1405,10 +1418,10 @@ uds_referral_descriptor_str(char * b, int blen, const uint8_t * dp,
!!(dp[2] & 0x1));
dp += 4;
for (k = 0, f = 1; (k + 4) < dlen; k += g, dp += g, ++f) {
- int tpgd = dp[3];
+ int ntpgd = dp[3];
uint64_t ull;
- g = (tpgd * 4) + 20;
+ g = (ntpgd * 4) + 20;
n += sg_scnpr(b + n, blen - n, "%s Descriptor %d\n", lip, f);
if ((k + g) > dlen) {
n += sg_scnpr(b + n, blen - n, "%s truncated descriptor, "
@@ -1421,7 +1434,7 @@ uds_referral_descriptor_str(char * b, int blen, const uint8_t * dp,
ull = sg_get_unaligned_be64(dp + 12);
n += sg_scnpr(b + n, blen - n, "%s last uds LBA: 0x%" PRIx64
"\n", lip, ull);
- for (j = 0; j < tpgd; ++j) {
+ for (j = 0; j < ntpgd; ++j) {
tp = dp + 20 + (j * 4);
decode_tpgs_state(tp[0] & 0xf, c, sizeof(c));
n += sg_scnpr(b + n, blen - n, "%s tpg: %d state: %s\n",
@@ -1453,10 +1466,10 @@ sg_get_sense_descriptors_str(const char * lip, const uint8_t * sbp,
uint16_t sct_sc;
bool processed;
const uint8_t * descp;
- const char * dtsp = " >> descriptor too short";
- const char * eccp = "Extended copy command";
- const char * ddp = "destination device";
char z[64];
+ static const char * dtsp = " >> descriptor too short";
+ static const char * eccp = "Extended copy command";
+ static const char * ddp = "destination device";
if ((NULL == b) || (blen <= 0))
return 0;
@@ -1821,8 +1834,8 @@ sg_get_sense_str(const char * lip, const uint8_t * sbp, int sb_len,
if (NULL == lip)
lip = "";
if ((NULL == sbp) || (sb_len < 1)) {
- n += sg_scnpr(cbp, cblen, "%s >>> sense buffer empty\n", lip);
- return n;
+ n += sg_scnpr(cbp, cblen, "%s >>> sense buffer empty\n", lip);
+ return n;
}
resp_code = 0x7f & sbp[0];
valid_info_fld = !!(sbp[0] & 0x80);
@@ -2811,17 +2824,14 @@ safe_strerror(int errnum)
return errstr;
}
-static void
+static int
trimTrailingSpaces(char * b)
{
- int k;
+ int n = strlen(b);
- for (k = ((int)strlen(b) - 1); k >= 0; --k) {
- if (' ' != b[k])
- break;
- }
- if ('\0' != b[k + 1])
- b[k + 1] = '\0';
+ while ((n > 0) && (' ' == b[n - 1]))
+ b[--n] = '\0';
+ return n;
}
/* Read binary starting at 'str' for 'len' bytes and output as ASCII
@@ -2932,22 +2942,23 @@ dStrHexErr(const char* str, int len, int no_ascii)
#define DSHS_LINE_BLEN 160 /* maximum characters per line */
#define DSHS_BPL 16 /* bytes per line */
-/* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space
- * separated) to 'b' not to exceed 'b_len' characters. Each line
- * starts with 'leadin' (NULL for no leadin) and there are 16 bytes
- * per line with an extra space between the 8th and 9th bytes. 'format'
- * is 0 for repeat in printable ASCII ('.' for non printable chars) to
- * right of each line; 1 don't (so just output ASCII hex). Note that
- * an address is not printed on each line preceding the hex data. Returns
- * number of bytes written to 'b' excluding the trailing '\0'.
- * The only difference between dStrHexStr() and hex2str() is the type of
- * the first argument. */
+/* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space separated)
+ * to 'b' not to exceed 'b_len' characters. Each line starts with 'leadin'
+ * (NULL for no leadin) and there are 16 bytes per line with an extra space
+ * between the 8th and 9th bytes. 'oformat' is 0 for repeat in printable ASCII
+ * ('.' for non printable chars) to right of each line; 1 don't (so just
+ * output ASCII hex). If 'oformat' is 2 output same as 1 but any LFs are
+ * replaced by space (and trailing spaces are trimmed). Note that an address
+ * is not printed on each line preceding the hex data. Returns number of bytes
+ * written to 'b' excluding the trailing '\0'. The only difference between
+ * dStrHexStr() and hex2str() is the type of the first argument. */
int
-dStrHexStr(const char * str, int len, const char * leadin, int format,
+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;
- bool want_ascii;
char buff[DSHS_LINE_BLEN + 2]; /* allow for trailing null */
char a[DSHS_BPL + 1]; /* printable ASCII bytes or '.' */
const char * p = str;
@@ -2959,7 +2970,6 @@ dStrHexStr(const char * str, int len, const char * leadin, int format,
}
if (b_len <= 0)
return 0;
- want_ascii = !format;
if (want_ascii) {
memset(a, ' ', DSHS_BPL);
a[DSHS_BPL] = '\0';
@@ -2995,9 +3005,9 @@ dStrHexStr(const char * str, int len, const char * leadin, int format,
prior_ascii_len, buff, a);
memset(a, ' ', DSHS_BPL);
} else
- n += sg_scnpr(b + n, b_len - n, "%s\n", buff);
+ n += sg_scnpr(b + n, b_len - n, "%s%c", buff, lf_or);
if (n >= (b_len - 1))
- return n;
+ goto fini;
memset(buff, ' ', DSHS_LINE_BLEN);
bpos = bpstart;
if (bpstart > 0)
@@ -3011,8 +3021,11 @@ dStrHexStr(const char * str, int len, const char * leadin, int format,
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\n", buff);
+ n += sg_scnpr(b + n, b_len - n, "%s%c", buff, lf_or);
}
+fini:
+ if (oformat > 1)
+ n = trimTrailingSpaces(b);
return n;
}
@@ -3029,14 +3042,14 @@ hex2stderr(const uint8_t * b_str, int len, int no_ascii)
}
int
-hex2str(const uint8_t * b_str, int len, const char * leadin, int format,
+hex2str(const uint8_t * b_str, int len, const char * leadin, int oformat,
int b_len, char * b)
{
- return dStrHexStr((const char *)b_str, len, leadin, format, b_len, b);
+ return dStrHexStr((const char *)b_str, len, leadin, oformat, b_len, b);
}
void
-hex2fp(const uint8_t * b_str, int len, const char * leadin, int format,
+hex2fp(const uint8_t * b_str, int len, const char * leadin, int oformat,
FILE * fp)
{
int k, num;
@@ -3048,7 +3061,7 @@ hex2fp(const uint8_t * b_str, int len, const char * leadin, int format,
}
for (k = 0; k < len; k += num) {
num = ((k + 64) < len) ? 64 : (len - k);
- hex2str(b_str + k, num, leadin, format, sizeof(b), b);
+ hex2str(b_str + k, num, leadin, oformat, sizeof(b), b);
fprintf(fp, "%s", b);
}
}
@@ -3393,7 +3406,7 @@ sg_get_llnum(const char * buf)
buf += n;
len -= n;
}
- /* following hack to keep C++ happy */
+ /* following cast hack to keep C++ happy */
cp = strpbrk((char *)buf, " \t,#-");
if (cp) {
len = cp - buf;
@@ -3542,11 +3555,12 @@ sg_get_llnum_nomult(const char * buf)
/* Read ASCII hex bytes or binary from fname (a file named '-' taken as
* stdin). If reading ASCII hex then there should be either one entry per
- * line or a comma, space or tab separated list of bytes. If no_space is
- * set then a string of ACSII hex digits is expected, 2 per byte. Everything
- * from and including a '#' on a line is ignored. Returns 0 if ok, or an
- * error code. If the error code is SG_LIB_LBA_OUT_OF_RANGE then mp_arr
- * would be exceeded and both mp_arr and mp_arr_len are written to. */
+ * line or a comma, space, hyphen or tab separated list of bytes. If
+ * no_space is * set then a string of ACSII hex digits is expected, 2 per
+ * byte. Everything from and including a '#' on a line is ignored. Returns
+ * 0 if ok, or an error code. If the error code is
+ * SG_LIB_LBA_OUT_OF_RANGE then mp_arr would be exceeded and both mp_arr
+ * and mp_arr_len are written to. */
int
sg_f2hex_arr(const char * fname, bool as_binary, bool no_space,
uint8_t * mp_arr, int * mp_arr_len, int max_arr_len)
@@ -3682,7 +3696,7 @@ sg_f2hex_arr(const char * fname, bool as_binary, bool no_space,
in_len -= m;
if ('#' == *lcp)
continue;
- k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t");
+ k = strspn(lcp, "0123456789aAbBcCdDeEfF ,-\t");
if ((k < in_len) && ('#' != lcp[k]) && ('\r' != lcp[k])) {
pr2ws("%s: syntax error at line %d, pos %d\n", __func__,
j + 1, m + k + 1);
@@ -3730,10 +3744,10 @@ sg_f2hex_arr(const char * fname, bool as_binary, bool no_space,
goto fini;
} else
mp_arr[off + k] = h;
- lcp = strpbrk(lcp, " ,\t");
+ lcp = strpbrk(lcp, " ,-\t");
if (NULL == lcp)
break;
- lcp += strspn(lcp, " ,\t");
+ lcp += strspn(lcp, " ,-\t");
if ('\0' == *lcp)
break;
} else {
@@ -3831,6 +3845,41 @@ sg_get_page_size(void)
#endif
}
+#if defined(SG_LIB_WIN32)
+#if defined(MSC_VER) || defined(__MINGW32__)
+/* windows.h already included above */
+#define sg_sleep_for(seconds) Sleep( (seconds) * 1000)
+#else
+#define sg_sleep_for(seconds) sleep(seconds)
+#endif
+#else
+#define sg_sleep_for(seconds) sleep(seconds)
+#endif
+
+void
+sg_sleep_secs(int num_secs)
+{
+ sg_sleep_for(num_secs);
+}
+
+void
+sg_warn_and_wait(const char * cmd_name, const char * dev_name,
+ bool stress_all)
+{
+ int k;
+ const char * stressp = stress_all ? "ALL d" : "D";
+ const char * will_mayp = stress_all ? "will" : "may";
+
+ for (k = 0; k < 3; ++k) {
+ printf("\nA %s command will commence in 15 seconds\n", cmd_name);
+ printf(" %sata on %s %s be DESTROYED%s\n", stressp, dev_name,
+ will_mayp, (stress_all ? "" : " or modified"));
+ printf(" Press control-C to abort\n");
+ sg_sleep_secs(5);
+ }
+ sg_sleep_secs(1);
+}
+
/* Returns pointer to heap (or NULL) that is aligned to a align_to byte
* boundary. Sends back *buff_to_free pointer in third argument that may be
* different from the return value. If it is different then the *buff_to_free
diff --git a/lib/sg_lib_data.c b/lib/sg_lib_data.c
index d0931eb7..3e291eb2 100644
--- a/lib/sg_lib_data.c
+++ b/lib/sg_lib_data.c
@@ -19,8 +19,8 @@
#include "sg_lib_data.h"
-const char * sg_lib_version_str = "2.88 20220305";
-/* spc6r06, sbc5r01, zbc2r12 */
+const char * sg_lib_version_str = "2.90 20220622";
+/* spc6r06, sbc5r01, zbc2r13 */
/* indexed by pdt; those that map to own index do not decay */
diff --git a/lib/sg_pr2serr.c b/lib/sg_pr2serr.c
index 5c869aee..9ae466b3 100644
--- a/lib/sg_pr2serr.c
+++ b/lib/sg_pr2serr.c
@@ -18,6 +18,15 @@
#include "sg_pr2serr.h"
#include "sg_json_builder.h"
+/* Comment out next line to remove dependency on sg_lib.h */
+#define SG_PRSE_SENSE_DECODE 1
+
+#ifdef SG_PRSE_SENSE_DECODE
+#include "sg_lib.h"
+#include "sg_lib_data.h"
+#include "sg_unaligned.h"
+#endif
+
#define sgj_opts_ev "SG3_UTILS_JSON_OPTS"
@@ -110,6 +119,9 @@ sgj_parse_opts(sgj_state * jsp, const char * j_optarg)
case '8':
jsp->pr_indent_size = 8;
break;
+ case 'a': /* abbreviated name expansion */
+ jsp->pr_ane = ! prev_negate;
+ break;
case 'e':
jsp->pr_exit_status = ! prev_negate;
break;
@@ -152,6 +164,7 @@ static void
sgj_def_opts(sgj_state * jsp)
{
jsp->pr_as_json = true;
+ jsp->pr_ane = false;
jsp->pr_exit_status = true;
jsp->pr_hex = false;
jsp->pr_leadin = true;
@@ -371,8 +384,8 @@ sgj_new_unattached_array(sgj_state * jsp)
}
sgj_opaque_p
-sgj_add_val_s(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- const char * value)
+sgj_add_nv_s(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ const char * value)
{
if (jsp && jsp->pr_as_json && value) {
if (name)
@@ -386,8 +399,8 @@ sgj_add_val_s(sgj_state * jsp, sgj_opaque_p jop, const char * name,
}
sgj_opaque_p
-sgj_add_val_i(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- int64_t value)
+sgj_add_nv_i(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ int64_t value)
{
if (jsp && jsp->pr_as_json) {
if (name)
@@ -402,8 +415,7 @@ sgj_add_val_i(sgj_state * jsp, sgj_opaque_p jop, const char * name,
}
sgj_opaque_p
-sgj_add_val_b(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- bool value)
+sgj_add_nv_b(sgj_state * jsp, sgj_opaque_p jop, const char * name, bool value)
{
if (jsp && jsp->pr_as_json) {
if (name)
@@ -418,8 +430,8 @@ sgj_add_val_b(sgj_state * jsp, sgj_opaque_p jop, const char * name,
/* jop will 'own' ua_jop (if returned value is non-NULL) */
sgj_opaque_p
-sgj_add_val_o(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- sgj_opaque_p ua_jop)
+sgj_add_nv_o(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ sgj_opaque_p ua_jop)
{
if (jsp && jsp->pr_as_json && ua_jop) {
if (name)
@@ -433,42 +445,166 @@ sgj_add_val_o(sgj_state * jsp, sgj_opaque_p jop, const char * name,
}
void
-sgj_add_name_pair_ihex(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- uint64_t value)
+sgj_add_nv_ihex(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ uint64_t value)
{
if ((NULL == jsp) || (NULL == name) || (! jsp->pr_as_json))
return;
else if (jsp->pr_hex) {
sgj_opaque_p jo2p =
- sgj_new_named_object(jsp, (jop ? jop : jsp->basep), name);
+ sgj_new_named_object(jsp, jop, name);
char b[64];
if (NULL == jo2p)
return;
- sgj_add_val_i(jsp, jo2p, "i", (int64_t)value);
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)value);
snprintf(b, sizeof(b), "%" PRIx64, value);
- sgj_add_val_s(jsp, jo2p, "hex", b);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
} else
- sgj_add_val_i(jsp, jop, name, (int64_t)value);
+ sgj_add_nv_i(jsp, jop, name, (int64_t)value);
}
+static const char * sc_mn_s = "meaning";
+
void
-sgj_add_name_pair_istr(sgj_state * jsp, sgj_opaque_p jop,
- const char * name, int64_t value,
- const char * str_name, const char * str)
+sgj_add_nv_istr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ int64_t val_i, const char * str_name, const char * val_s)
{
if ((NULL == jsp) || (! jsp->pr_as_json))
return;
else if (jsp->pr_string) {
sgj_opaque_p jo2p =
- sgj_new_named_object(jsp, (jop ? jop : jsp->basep), name);
+ sgj_new_named_object(jsp, jop, name);
if (NULL == jo2p)
return;
- sgj_add_val_i(jsp, jo2p, "i", (int64_t)value);
- if (str)
- sgj_add_val_s(jsp, jo2p, str_name ? str_name : "string", str);
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ if (val_s)
+ sgj_add_nv_s(jsp, jo2p, str_name ? str_name : sc_mn_s, val_s);
} else
- sgj_add_val_i(jsp, jop, name, value);
+ sgj_add_nv_i(jsp, jop, name, val_i);
+}
+
+void
+sgj_add_nv_ihexstr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ int64_t val_i, const char * str_name, const char * val_s)
+{
+ if ((NULL == jsp) || (! jsp->pr_as_json))
+ return;
+ if ((! jsp->pr_hex) && (! jsp->pr_string))
+ sgj_add_nv_i(jsp, jop, name, val_i);
+ else {
+ char b[64];
+ sgj_opaque_p jo2p =
+ sgj_new_named_object(jsp, jop, name);
+
+ if (NULL == jo2p)
+ return;
+ if (jsp->pr_string) {
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ if (jsp->pr_hex) {
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ }
+ if (val_s)
+ sgj_add_nv_s(jsp, jo2p, str_name ? str_name : sc_mn_s, val_s);
+ } else if (jsp->pr_hex) {
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ }
+ }
+}
+
+static const char * sc_ane_s = "abbreviated_name_expansion";
+
+void
+sgj_add_nv_ihex_ane(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ int64_t val_i, bool want_hex, const char * ane_s)
+{
+ bool as_hex = jsp->pr_hex && want_hex;
+ bool as_ane = jsp->pr_ane && ane_s;
+
+ if ((NULL == jsp) || (! jsp->pr_as_json))
+ return;
+ if (! (as_hex || as_ane))
+ sgj_add_nv_i(jsp, jop, name, val_i);
+ else {
+ char b[64];
+ sgj_opaque_p jo2p =
+ sgj_new_named_object(jsp, jop, name);
+
+ if (NULL == jo2p)
+ return;
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ if (as_ane) {
+ if (jsp->pr_hex && want_hex) {
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ }
+ sgj_add_nv_s(jsp, jo2p, sc_ane_s, ane_s);
+ } else if (as_hex) {
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ }
+ }
+}
+
+void
+sgj_add_nv_hex_bytes(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ const uint8_t * byte_arr, int num_bytes)
+{
+ int blen = num_bytes * 4;
+ char * bp;
+
+ if ((NULL == jsp) || (! jsp->pr_as_json) || (! jsp->pr_hex))
+ return;
+ bp = (char *)calloc(blen + 4, 1);
+ if (bp) {
+ hex2str(byte_arr, num_bytes, NULL, 2, blen, bp);
+ sgj_add_nv_s(jsp, jop, name, bp);
+ free(bp);
+ }
+}
+
+void
+sgj_add_nv_ihexstr_ane(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ int64_t val_i, bool want_hex, const char * str_name,
+ const char * val_s, const char * ane_s)
+{
+ bool as_hex = jsp->pr_hex && want_hex;
+ bool as_str = jsp->pr_string && val_s;
+ bool as_ane = jsp->pr_ane && ane_s;
+ const char * sname = str_name ? str_name : sc_mn_s;
+
+ if ((NULL == jsp) || (! jsp->pr_as_json))
+ return;
+ if (! (as_hex || as_ane || as_str))
+ sgj_add_nv_i(jsp, jop, name, val_i);
+ else {
+ char b[64];
+ sgj_opaque_p jo2p =
+ sgj_new_named_object(jsp, jop, name);
+
+ if (NULL == jo2p)
+ return;
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ if (as_ane) {
+ if (as_hex) {
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ }
+ if (as_str) {
+ sgj_add_nv_s(jsp, jo2p, sname, val_s);
+ }
+ sgj_add_nv_s(jsp, jo2p, sc_ane_s, ane_s);
+ } else if (as_hex) {
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ if (as_str)
+ sgj_add_nv_s(jsp, jo2p, sname, val_s);
+ } else if (as_str)
+ sgj_add_nv_s(jsp, jo2p, sname, val_s);
+ }
}
/* Returns number of characters placed in 'out' excluding trailing NULL */
@@ -511,8 +647,8 @@ sgj_jsonify_name(const char * in, char * out, int maxlen_out)
}
static void
-sgj_pr_twin_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep, json_value * jvp)
+sgj_pr_hr_js_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep, json_value * jvp)
{
bool eaten = false;
bool as_json = (jsp && jsp->pr_as_json);
@@ -631,33 +767,889 @@ sgj_pr_twin_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
}
void
-sgj_pr_twin_vs(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep,
- const char * value)
+sgj_pr_hr_js_vs(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep,
+ const char * value)
{
json_value * jvp;
/* make json_value even if jsp->pr_as_json is false */
jvp = value ? json_string_new(value) : NULL;
- sgj_pr_twin_xx(jsp, jop, leadin_sp, name, sep, jvp);
+ sgj_pr_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp);
}
void
-sgj_pr_twin_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep, int64_t value)
+sgj_pr_hr_js_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep, int64_t value)
{
json_value * jvp;
jvp = json_integer_new(value);
- sgj_pr_twin_xx(jsp, jop, leadin_sp, name, sep, jvp);
+ sgj_pr_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp);
}
void
-sgj_pr_twin_vb(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep, bool value)
+sgj_pr_hr_js_vb(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep, bool value)
{
json_value * jvp;
jvp = json_boolean_new(value);
- sgj_pr_twin_xx(jsp, jop, leadin_sp, name, sep, jvp);
+ sgj_pr_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp);
+}
+
+#ifdef SG_PRSE_SENSE_DECODE
+
+static const char * dtsp = "descriptor too short";
+static const char * sksvp = "sense-key specific valid";
+static const char * ddep = "designation_descriptor_error";
+static const char * naa_exp = "Network Address Authority";
+static const char * aoi_exp = "IEEE-Administered Organizational Identifier";
+
+bool
+sgj_get_designation_descriptor(sgj_state * jsp, sgj_opaque_p jop,
+ const uint8_t * ddp, int dd_len)
+{
+ int p_id, piv, c_set, assoc, desig_type, d_id, naa;
+ int n, aoi, vsi, dlen;
+ uint64_t ull;
+ const uint8_t * ip;
+ char e[80];
+ char b[256];
+ const char * cp;
+ const char * naa_sp;
+ static const int blen = sizeof(b);
+ static const int elen = sizeof(e);
+
+ if (dd_len < 4) {
+ sgj_add_nv_s(jsp, jop, ddep, "too short");
+ return false;
+ }
+ dlen = ddp[3];
+ if (dlen > (dd_len - 4)) {
+ snprintf(e, elen, "too long: says it is %d bytes, but given %d "
+ "bytes\n", dlen, dd_len - 4);
+ sgj_add_nv_s(jsp, jop, ddep, e);
+ return false;
+ }
+ ip = ddp + 4;
+ p_id = ((ddp[0] >> 4) & 0xf);
+ c_set = (ddp[0] & 0xf);
+ piv = ((ddp[1] & 0x80) ? 1 : 0);
+ assoc = ((ddp[1] >> 4) & 0x3);
+ desig_type = (ddp[1] & 0xf);
+ cp = sg_get_desig_assoc_str(assoc);
+ if (assoc == 3)
+ cp = "Reserved [0x3]"; /* should not happen */
+ sgj_add_nv_ihexstr(jsp, jop, "association", assoc, NULL, cp);
+ cp = sg_get_desig_type_str(desig_type);
+ if (NULL == cp)
+ cp = "unknown";
+ sgj_add_nv_ihexstr(jsp, jop, "designator_type", desig_type,
+ NULL, cp);
+ cp = sg_get_desig_code_set_str(c_set);
+ if (NULL == cp)
+ cp = "unknown";
+ sgj_add_nv_ihexstr(jsp, jop, "code_set", desig_type,
+ NULL, cp);
+ sgj_add_nv_ihex_ane(jsp, jop, "piv", piv, false,
+ "Protocol Identifier Valid");
+ sg_get_trans_proto_str(p_id, elen, e);
+ 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);
+ break;
+ case 1: /* T10 vendor identification */
+ n = (dlen < 8) ? dlen : 8;
+ snprintf(b, blen, "%.*s", n, ip);
+ sgj_add_nv_s(jsp, jop, "t10_vendor_identification", b);
+ b[0] = '\0';
+ if (dlen > 8)
+ snprintf(b, blen, "%.*s", dlen - 8, ip + 8);
+ sgj_add_nv_s(jsp, jop, "vendor_specific_identifier", b);
+ break;
+ case 2: /* EUI-64 based */
+ sgj_add_nv_i(jsp, jop, "eui_64_based_designator_length", dlen);
+ ull = sg_get_unaligned_be64(ip);
+ switch (dlen) {
+ case 8:
+ sgj_add_nv_ihex(jsp, jop, "ieee_identifier", ull);
+ break;
+ case 12:
+ sgj_add_nv_ihex(jsp, jop, "ieee_identifier", ull);
+ sgj_add_nv_ihex(jsp, jop, "directory_id",
+ sg_get_unaligned_be32(ip + 8));
+ break;
+ case 16:
+ sgj_add_nv_ihex(jsp, jop, "identifier_extension", ull);
+ sgj_add_nv_ihex(jsp, jop, "ieee_identifier",
+ sg_get_unaligned_be64(ip + 8));
+ break;
+ default:
+ sgj_add_nv_s(jsp, jop, "eui_64", "decoding falied");
+ break;
+ }
+ break;
+ case 3: /* NAA <n> */
+ sgj_add_nv_hex_bytes(jsp, jop, "full_naa_in_hex", ip, dlen);
+ naa = (ip[0] >> 4) & 0xff;
+ switch (naa) {
+ case 2:
+ naa_sp = "IEEE Extended";
+ sgj_add_nv_ihexstr_ane(jsp, jop, "naa", naa, false, NULL, naa_sp,
+ naa_exp);
+ d_id = (((ip[0] & 0xf) << 8) | ip[1]);
+ sgj_add_nv_ihex(jsp, jop, "vendor_specific_identifier_a", d_id);
+ aoi = sg_get_unaligned_be24(ip + 2);
+ sgj_add_nv_ihex_ane(jsp, jop, "aoi", aoi, true, aoi_exp);
+ vsi = sg_get_unaligned_be24(ip + 5);
+ sgj_add_nv_ihex(jsp, jop, "vendor_specific_identifier_b", vsi);
+ break;
+ case 3:
+ naa_sp = "Locally Assigned";
+ sgj_add_nv_ihexstr_ane(jsp, jop, "naa", naa, false, NULL, naa_sp,
+ naa_exp);
+ ull = sg_get_unaligned_be64(ip + 0) & 0xfffffffffffffffULL;
+ sgj_add_nv_ihex(jsp, jop, "locally_administered_value", ull);
+ break;
+ case 5:
+ naa_sp = "IEEE Registered";
+ sgj_add_nv_ihexstr_ane(jsp, jop, "naa", naa, false, NULL, naa_sp,
+ naa_exp);
+ aoi = (sg_get_unaligned_be32(ip + 0) >> 4) & 0xffffff;
+ sgj_add_nv_ihex_ane(jsp, jop, "aoi", aoi, true, aoi_exp);
+ ull = sg_get_unaligned_be48(ip + 2) & 0xfffffffffULL;
+ sgj_add_nv_ihex(jsp, jop, "vendor_specific_identifier", ull);
+ break;
+ case 6:
+ naa_sp = "IEEE Registered Extended";
+ sgj_add_nv_ihexstr_ane(jsp, jop, "naa", naa, false, NULL, naa_sp,
+ naa_exp);
+ aoi = (sg_get_unaligned_be32(ip + 0) >> 4) & 0xffffff;
+ sgj_add_nv_ihex_ane(jsp, jop, "aoi", aoi, true, aoi_exp);
+ ull = sg_get_unaligned_be48(ip + 2) & 0xfffffffffULL;
+ sgj_add_nv_ihex(jsp, jop, "vendor_specific_identifier", ull);
+ ull = sg_get_unaligned_be64(ip + 8);
+ sgj_add_nv_ihex(jsp, jop, "vendor_specific_identifier_extension",
+ ull);
+ break;
+ default:
+ snprintf(b, blen, "unknown NAA value=0x%x", naa);
+ sgj_add_nv_ihexstr_ane(jsp, jop, "naa", naa, true, NULL, b,
+ naa_exp);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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 (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]);
+ } 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]);
+ } 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);
+ break;
+ case 0xa: /* UUID identifier */
+ n += sg_t10_uuid_desig2str(ip, dlen, c_set, do_long, false, lip,
+ blen - n, b + n);
+ break;
+#endif
+ default: /* reserved */
+ hex2str(ip, dlen, NULL, 1, blen, b);
+ sgj_add_nv_s(jsp, jop, "reserved_designator_hex", b);
+ break;
+ }
+ return true;
}
+
+static void
+sgj_progress_indication(sgj_state * jsp, sgj_opaque_p jop,
+ uint16_t prog_indic, bool is_another)
+{
+ uint32_t progress, pr, rem;
+ sgj_opaque_p jo2p;
+ char b[64];
+
+ if (is_another)
+ jo2p = sgj_new_named_object(jsp, jop, "another_progress_indication");
+ else
+ jo2p = sgj_new_named_object(jsp, jop, "progress_indication");
+ if (NULL == jo2p)
+ return;
+ progress = prog_indic;
+ sgj_add_nv_i(jsp, jo2p, "i", progress);
+ snprintf(b, sizeof(b), "%x", progress);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ progress *= 100;
+ pr = progress / 65536;
+ rem = (progress % 65536) / 656;
+ snprintf(b, sizeof(b), "%d.02%d%%\n", pr, rem);
+ sgj_add_nv_s(jsp, jo2p, "percentage", b);
+}
+
+static bool
+sgj_decode_sks(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * dp, int dlen,
+ int sense_key)
+{
+ switch (sense_key) {
+ case SPC_SK_ILLEGAL_REQUEST:
+ if (dlen < 3) {
+ sgj_add_nv_s(jsp, jop, "illegal_request_sks", dtsp);
+ return false;
+ }
+ sgj_add_nv_ihex_ane(jsp, jop, "sksv", !! (dp[0] & 0x80), false,
+ sksvp);
+ sgj_add_nv_ihex_ane(jsp, jop, "c_d", !! (dp[0] & 0x40), false,
+ "c: cdb; d: data-out");
+ sgj_add_nv_ihex_ane(jsp, jop, "bpv", !! (dp[0] & 0x8), false,
+ "bit pointer (index) valid");
+ sgj_add_nv_i(jsp, jop, "bit_pointer", dp[0] & 0x7);
+ sgj_add_nv_ihex(jsp, jop, "field_pointer",
+ sg_get_unaligned_be16(dp + 1));
+ break;
+ case SPC_SK_HARDWARE_ERROR:
+ case SPC_SK_MEDIUM_ERROR:
+ case SPC_SK_RECOVERED_ERROR:
+ if (dlen < 3) {
+ sgj_add_nv_s(jsp, jop, "actual_retry_count_sks", dtsp);
+ return false;
+ }
+ sgj_add_nv_ihex_ane(jsp, jop, "sksv", !! (dp[0] & 0x80), false,
+ sksvp);
+ sgj_add_nv_ihex(jsp, jop, "actual_retry_count",
+ sg_get_unaligned_be16(dp + 1));
+ break;
+ case SPC_SK_NO_SENSE:
+ case SPC_SK_NOT_READY:
+ if (dlen < 7) {
+ sgj_add_nv_s(jsp, jop, "progress_indication_sks", dtsp);
+ return false;
+ }
+ sgj_add_nv_ihex_ane(jsp, jop, "sksv", !! (dp[0] & 0x80), false,
+ sksvp);
+ sgj_progress_indication(jsp, jop, sg_get_unaligned_be16(dp + 1),
+ false);
+ break;
+ case SPC_SK_COPY_ABORTED:
+ if (dlen < 7) {
+ sgj_add_nv_s(jsp, jop, "segment_indication_sks", dtsp);
+ return false;
+ }
+ sgj_add_nv_ihex_ane(jsp, jop, "sksv", !! (dp[0] & 0x80), false,
+ sksvp);
+ sgj_add_nv_ihex_ane(jsp, jop, "sd", !! (dp[0] & 0x20), false,
+ "field pointer relative to: 1->segment "
+ "descriptor, 0->parameter list");
+ sgj_add_nv_ihex_ane(jsp, jop, "bpv", !! (dp[0] & 0x8), false,
+ "bit pointer (index) valid");
+ sgj_add_nv_i(jsp, jop, "bit_pointer", dp[0] & 0x7);
+ sgj_add_nv_ihex(jsp, jop, "field_pointer",
+ sg_get_unaligned_be16(dp + 1));
+ break;
+ case SPC_SK_UNIT_ATTENTION:
+ if (dlen < 7) {
+ sgj_add_nv_s(jsp, jop, "segment_indication_sks", dtsp);
+ return false;
+ }
+ sgj_add_nv_ihex_ane(jsp, jop, "sksv", !! (dp[0] & 0x80), false,
+ sksvp);
+ sgj_add_nv_i(jsp, jop, "overflow", !! (dp[0] & 0x80));
+ break;
+ default:
+ sgj_add_nv_ihex(jsp, jop, "unexpected_sense_key", sense_key);
+ return false;
+ }
+ return true;
+}
+
+#define TPGS_STATE_OPTIMIZED 0x0
+#define TPGS_STATE_NONOPTIMIZED 0x1
+#define TPGS_STATE_STANDBY 0x2
+#define TPGS_STATE_UNAVAILABLE 0x3
+#define TPGS_STATE_OFFLINE 0xe
+#define TPGS_STATE_TRANSITIONING 0xf
+
+static int
+decode_tpgs_state(int st, char * b, int blen)
+{
+ switch (st) {
+ case TPGS_STATE_OPTIMIZED:
+ return sg_scnpr(b, blen, "active/optimized");
+ case TPGS_STATE_NONOPTIMIZED:
+ return sg_scnpr(b, blen, "active/non optimized");
+ case TPGS_STATE_STANDBY:
+ return sg_scnpr(b, blen, "standby");
+ case TPGS_STATE_UNAVAILABLE:
+ return sg_scnpr(b, blen, "unavailable");
+ case TPGS_STATE_OFFLINE:
+ return sg_scnpr(b, blen, "offline");
+ case TPGS_STATE_TRANSITIONING:
+ return sg_scnpr(b, blen, "transitioning between states");
+ default:
+ return sg_scnpr(b, blen, "unknown: 0x%x", st);
+ }
+}
+
+static bool
+sgj_uds_referral_descriptor(sgj_state * jsp, sgj_opaque_p jop,
+ const uint8_t * dp, int alen)
+{
+ int dlen = alen - 2;
+ int k, j, g, f, aas;
+ uint64_t ull;
+ const uint8_t * tp;
+ sgj_opaque_p jap, jo2p, ja2p, jo3p;
+ char c[40];
+
+ sgj_add_nv_ihex_ane(jsp, jop, "not_all_r", (dp[2] & 0x1), false,
+ "Not all referrals");
+ dp += 4;
+ jap = sgj_new_named_array(jsp, jop,
+ "user_data_segment_referral_descriptor");
+ for (k = 0, f = 1; (k + 4) < dlen; k += g, dp += g, ++f) {
+ int ntpgd = dp[3];
+
+ jo2p = sgj_new_unattached_object(jsp);
+ g = (ntpgd * 4) + 20;
+ sgj_add_nv_ihex(jsp, jo2p, "number_of_target_port_group_descriptors",
+ ntpgd);
+ if ((k + g) > dlen) {
+ sgj_add_nv_i(jsp, jo2p, "truncated_descriptor_dlen", dlen);
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
+ return false;
+ }
+ ull = sg_get_unaligned_be64(dp + 4);
+ sgj_add_nv_ihex(jsp, jo2p, "first_user_date_sgment_lba", ull);
+ ull = sg_get_unaligned_be64(dp + 12);
+ sgj_add_nv_ihex(jsp, jo2p, "last_user_date_sgment_lba", ull);
+ ja2p = sgj_new_named_array(jsp, jo2p, "target_port_group_descriptor");
+ for (j = 0; j < ntpgd; ++j) {
+ jo3p = sgj_new_unattached_object(jsp);
+ tp = dp + 20 + (j * 4);
+ aas = tp[0] & 0xf;
+ decode_tpgs_state(aas, c, sizeof(c));
+ sgj_add_nv_ihexstr(jsp, jo3p, "asymmetric_access_state", aas,
+ NULL, c);
+ sgj_add_nv_ihex(jsp, jo3p, "target_port_group",
+ sg_get_unaligned_be16(tp + 2));
+ sgj_add_nv_o(jsp, ja2p, NULL /* name */, jo3p);
+ }
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
+ }
+ return true;
+}
+
+static bool
+sgj_get_sense_descriptors(sgj_state * jsp, sgj_opaque_p jop,
+ const struct sg_scsi_sense_hdr * sshp,
+ const uint8_t * sbp, int sb_len)
+{
+ 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;
+ sgj_opaque_p jap, jo2p, jo3p;
+ char b[80];
+ static const int blen = sizeof(b);
+ static const char * parsing = "parsing_error";
+#if 0
+ static const char * eccp = "Extended copy command";
+ static const char * ddp = "destination device";
+#endif
+
+ add_sb_len = sshp->additional_length;
+ add_sb_len = (add_sb_len < sb_len) ? add_sb_len : sb_len;
+ sense_key = sshp->sense_key;
+ jap = sgj_new_named_array(jsp, jop, "sense_data_descriptor");
+
+ for (descp = sbp, k = 0; (k < add_sb_len);
+ k += desc_len, descp += desc_len) {
+ int add_d_len = (k < (add_sb_len - 1)) ? descp[1] : -1;
+
+ jo2p = sgj_new_unattached_object(jsp);
+ if ((k + add_d_len + 2) > add_sb_len)
+ add_d_len = add_sb_len - k - 2;
+ desc_len = add_d_len + 2;
+ processed = true;
+ dt = descp[0];
+ switch (dt) {
+ case 0:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt,
+ NULL, "Information");
+ if (add_d_len >= 10) {
+ int valid = !! (0x80 & descp[2]);
+ sgj_add_nv_ihexstr(jsp, jo2p, "valid", valid, NULL,
+ valid ? "as per T10" : "Vendor specific");
+ sgj_add_nv_ihex(jsp, jo2p, "information",
+ sg_get_unaligned_be64(descp + 4));
+ } else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 1:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt,
+ NULL, "Command specific");
+ if (add_d_len >= 10) {
+ sgj_add_nv_ihex(jsp, jo2p, "command_specific_information",
+ sg_get_unaligned_be64(descp + 4));
+ } else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 2: /* Sense Key Specific */
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Sense key specific");
+ processed = sgj_decode_sks(jsp, jo2p, descp + 4, desc_len - 4,
+ sense_key);
+ break;
+ case 3:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Field replaceable unit code");
+ if (add_d_len >= 2)
+ sgj_add_nv_ihex(jsp, jo2p, "field_replaceable_unit_code",
+ descp[3]);
+ else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 4:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Stream commands");
+ if (add_d_len >= 2) {
+ sgj_add_nv_i(jsp, jo2p, "filemark", !! (descp[3] & 0x80));
+ sgj_add_nv_ihex_ane(jsp, jo2p, "eom", !! (descp[3] & 0x40),
+ false, "End Of Medium");
+ sgj_add_nv_ihex_ane(jsp, jo2p, "ili", !! (descp[3] & 0x20),
+ false, "Incorrect Length Indicator");
+ } else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 5:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Block commands");
+ if (add_d_len >= 2)
+ sgj_add_nv_ihex_ane(jsp, jo2p, "ili", !! (descp[3] & 0x20),
+ false, "Incorrect Length Indicator");
+ else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 6:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "OSD object identification");
+ sgj_add_nv_s(jsp, jo2p, parsing, "Unsupported");
+ processed = false;
+ break;
+ case 7:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "OSD response integrity check value");
+ sgj_add_nv_s(jsp, jo2p, parsing, "Unsupported");
+ break;
+ case 8:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "OSD attribute identification");
+ sgj_add_nv_s(jsp, jo2p, parsing, "Unsupported");
+ processed = false;
+ break;
+ case 9: /* this is defined in SAT (SAT-2) */
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "ATA status return");
+ if (add_d_len >= 12) {
+ sgj_add_nv_i(jsp, jo2p, "extend", !! (descp[2] & 1));
+ sgj_add_nv_ihex(jsp, jo2p, "error", descp[3]);
+ sgj_add_nv_ihex(jsp, jo2p, "count",
+ sg_get_unaligned_be16(descp + 4));
+ ull = ((uint64_t)descp[10] << 40) |
+ ((uint64_t)descp[8] << 32) |
+ (descp[6] << 24) |
+ (descp[11] << 16) |
+ (descp[9] << 8) |
+ descp[7];
+ sgj_add_nv_ihex(jsp, jo2p, "lba", ull);
+ sgj_add_nv_ihex(jsp, jo2p, "device", descp[12]);
+ sgj_add_nv_ihex(jsp, jo2p, "status", descp[13]);
+ } else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 0xa:
+ /* Added in SPC-4 rev 17, became 'Another ...' in rev 34 */
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Another progress indication");
+ if (add_d_len < 6) {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ break;
+ }
+ sgj_add_nv_ihex(jsp, jo2p, "another_sense_key", descp[2]);
+ sgj_add_nv_ihex(jsp, jo2p, "another_additional_sense_code",
+ descp[3]);
+ sgj_add_nv_ihex(jsp, jo2p,
+ "another_additional_sense_code_qualifier",
+ descp[4]);
+ sgj_progress_indication(jsp, jo2p,
+ sg_get_unaligned_be16(descp + 6), true);
+ break;
+ case 0xb: /* Added in SPC-4 rev 23, defined in SBC-3 rev 22 */
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "User data segment referral");
+ if (add_d_len < 2) {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ break;
+ }
+ if (! sgj_uds_referral_descriptor(jsp, jo2p, descp, add_d_len)) {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 0xc: /* Added in SPC-4 rev 28 */
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Forwarded sense data");
+ if (add_d_len < 2) {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ break;
+ }
+ sgj_add_nv_ihex_ane(jsp, jo2p, "fsdt", !! (0x80 & descp[2]),
+ NULL, "Forwarded Sense Data Truncated");
+ sds = (0x7 & descp[2]);
+ if (sds < 1)
+ snprintf(b, blen, "%s [%d]", "Unknown", sds);
+ else if (sds > 9)
+ snprintf(b, blen, "%s [%d]", "Reserved", sds);
+ else {
+ n = 0;
+ n += sg_scnpr(b + n, blen - n, "EXTENDED COPY command copy %s",
+ (sds == 1) ? "source" : "destination");
+ if (sds > 1)
+ n += sg_scnpr(b + n, blen - n, " %d", sds - 1);
+ }
+ sgj_add_nv_ihexstr(jsp, jo2p, "sense_data_source",
+ (0x7 & descp[2]), NULL, b);
+ jo3p = sgj_new_named_object(jsp, jo2p, "forwarded_sense_data");
+ sgj_get_sense(jsp, jo3p, descp + 4, desc_len - 4);
+ 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,
+ "Direct-access block device");
+ if (add_d_len < 28) {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ break;
+ }
+ 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");
+ processed = sgj_decode_sks(jsp, jo2p, descp + 4, desc_len - 4,
+ sense_key);
+ sgj_add_nv_ihex(jsp, jo2p, "field_replaceable_unit_code",
+ descp[7]);
+ sgj_add_nv_ihex(jsp, jo2p, "information",
+ sg_get_unaligned_be64(descp + 8));
+ 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);
+ break;
+ case 0xf: /* Added in SPC-5 rev 10 (for Write buffer) */
+ n += sg_scnpr(b + n, blen - n, "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);
+ break;
+ case 0xde: /* NVME Status Field; vendor (sg3_utils) specific */
+ n += sg_scnpr(b + n, blen - n, "NVMe Status: ");
+ 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]));
+ 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));
+ }
+ 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);
+ 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;
+}
+
+#define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d /* corresponding ASC is 0 */
+
+/* Fetch sense information */
+bool
+sgj_get_sense(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * sbp,
+ int sb_len)
+{
+ bool descriptor_format = false;
+ bool sdat_ovfl = false;
+ bool ret = true;
+ bool valid_info_fld;
+ int len, n;
+ uint32_t info;
+ uint8_t resp_code;
+ const char * ebp = NULL;
+ char ebuff[64];
+ char b[256];
+ struct sg_scsi_sense_hdr ssh;
+ static int blen = sizeof(b);
+ static int elen = sizeof(ebuff);
+
+ if ((NULL == sbp) || (sb_len < 1)) {
+ snprintf(ebuff, elen, "sense buffer empty\n");
+ ebp = ebuff;
+ ret = false;
+ goto fini;
+ }
+ resp_code = 0x7f & sbp[0];
+ valid_info_fld = !!(sbp[0] & 0x80);
+ len = sb_len;
+ if (! sg_scsi_normalize_sense(sbp, sb_len, &ssh)) {
+ ebp = "unable to normalize sense buffer";
+ ret = false;
+ goto fini;
+ }
+ /* We have been able to normalize the sense buffer */
+ switch (resp_code) {
+ case 0x70: /* fixed, current */
+ ebp = "Fixed format, current";
+ len = (sb_len > 7) ? (sbp[7] + 8) : sb_len;
+ len = (len > sb_len) ? sb_len : len;
+ sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false;
+ break;
+ case 0x71: /* fixed, deferred */
+ /* error related to a previous command */
+ ebp = "Fixed format, <<<deferred>>>";
+ len = (sb_len > 7) ? (sbp[7] + 8) : sb_len;
+ len = (len > sb_len) ? sb_len : len;
+ sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false;
+ break;
+ case 0x72: /* descriptor, current */
+ descriptor_format = true;
+ ebp = "Descriptor format, current";
+ sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false;
+ break;
+ case 0x73: /* descriptor, deferred */
+ descriptor_format = true;
+ ebp = "Descriptor format, <<<deferred>>>";
+ sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false;
+ break;
+ default:
+ sg_scnpr(ebuff, elen, "Unknown code: 0x%x", resp_code);
+ ebp = ebuff;
+ break;
+ }
+ sgj_add_nv_ihexstr(jsp, jop, "response_code", resp_code, NULL, ebp);
+ sgj_add_nv_b(jsp, jop, "descriptor_format", descriptor_format);
+ sgj_add_nv_ihex_ane(jsp, jop, "sdat_ovfl", sdat_ovfl, false,
+ "Sense data overflow");
+ sgj_add_nv_ihexstr(jsp, jop, "sense_key", ssh.sense_key, NULL,
+ sg_lib_sense_key_desc[ssh.sense_key]);
+ sgj_add_nv_ihex(jsp, jop, "additional_sense_code", ssh.asc);
+ sgj_add_nv_ihex(jsp, jop, "additional_sense_code_qualifier", ssh.ascq);
+ sgj_add_nv_s(jsp, jop, "additional_sense_str",
+ sg_get_additional_sense_str(ssh.asc, ssh.ascq, false,
+ blen, b));
+ if (descriptor_format) {
+ if (len > 8) {
+ ret = sgj_get_sense_descriptors(jsp, jop, &ssh, sbp + 8, len - 8);
+ if (ret == false) {
+ ebp = "unable to decode sense descriptor";
+ goto fini;
+ }
+ }
+ } else if ((len > 12) && (0 == ssh.asc) &&
+ (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) {
+ /* SAT ATA PASS-THROUGH fixed format */
+ sgj_add_nv_ihex(jsp, jop, "error", sbp[3]);
+ sgj_add_nv_ihex(jsp, jop, "status", sbp[4]);
+ sgj_add_nv_ihex(jsp, jop, "device", sbp[5]);
+ sgj_add_nv_i(jsp, jop, "extend", !! (0x80 & sbp[8]));
+ sgj_add_nv_i(jsp, jop, "count_upper_nonzero", !! (0x40 & sbp[8]));
+ sgj_add_nv_i(jsp, jop, "lba_upper_nonzero", !! (0x20 & sbp[8]));
+ sgj_add_nv_i(jsp, jop, "log_index", (0x7 & sbp[8]));
+ sgj_add_nv_i(jsp, jop, "lba", sg_get_unaligned_le24(sbp + 9));
+ } else if (len > 2) { /* fixed format */
+ sgj_add_nv_i(jsp, jop, "valid", valid_info_fld);
+ sgj_add_nv_i(jsp, jop, "filemark", !! (sbp[2] & 0x80));
+ sgj_add_nv_ihex_ane(jsp, jop, "eom", !! (sbp[2] & 0x40),
+ false, "End Of Medium");
+ sgj_add_nv_ihex_ane(jsp, jop, "ili", !! (sbp[2] & 0x20),
+ false, "Incorrect Length Indicator");
+ info = sg_get_unaligned_be32(sbp + 3);
+ sgj_add_nv_ihex(jsp, jop, "information", info);
+ sgj_add_nv_ihex(jsp, jop, "additional_sense_length", sbp[7]);
+ if (sb_len > 11) {
+ info = sg_get_unaligned_be32(sbp + 8);
+ sgj_add_nv_ihex(jsp, jop, "command_specific_information", info);
+ }
+ if (sb_len > 14)
+ sgj_add_nv_ihex(jsp, jop, "field_replaceable_unit_code", sbp[14]);
+ if (sb_len > 17)
+ sgj_decode_sks(jsp, jop, sbp + 15, sb_len - 15, ssh.sense_key);
+ n = sbp[7];
+ n = (sb_len > n) ? n : sb_len;
+ sgj_add_nv_ihex(jsp, jop, "number_of_bytes_beyond_18",
+ (n > 18) ? n - 18 : 0);
+ } else {
+ snprintf(ebuff, sizeof(ebuff), "sb_len=%d too short", sb_len);
+ ebp = ebuff;
+ ret = false;
+ }
+fini:
+ if ((! ret) && ebp)
+ sgj_add_nv_s(jsp, jop, "sense_decode_error", ebp);
+ return ret;
+}
+
+#endif
diff --git a/lib/sg_pt_haiku.c b/lib/sg_pt_haiku.c
index c9ed291c..6b1ed222 100644
--- a/lib/sg_pt_haiku.c
+++ b/lib/sg_pt_haiku.c
@@ -148,7 +148,7 @@ set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb,
if (ptp->raw_command.command[i])
++ptp->in_err;
memcpy(ptp->raw_command.command, cdb, cdb_len);
- ptp->raw_command.command_length = (uint8)cdb_len;
+ ptp->raw_command.command_length = (uint8_t)cdb_len;
}
void
diff --git a/scripts/rescan-scsi-bus.sh b/scripts/rescan-scsi-bus.sh
index 09e22a4a..27cc35cd 100755
--- a/scripts/rescan-scsi-bus.sh
+++ b/scripts/rescan-scsi-bus.sh
@@ -323,7 +323,7 @@ testonline ()
TYPE=$(printtype $IPTYPE)
if ! procscsiscsi ; then
- echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV removed.\n\n\n"
+ echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV removed. ${norm}\n\n\n"
return 2
fi
TMPSTR=$(echo "$SCSISTR" | grep 'Vendor:')
@@ -414,7 +414,7 @@ idlist ()
if [ -n "$oldid" ] ; then
if [ -d /sys/class/scsi_device/$oldid ] ; then
hcil=${oldid}
- printf "\r${green}NEW: %s" "$norm"
+ printf "\r${green}NEW: %s ${norm}"
testexist
if [ "$SCSISTR" ] ; then
incrfound "$hcil"
@@ -486,7 +486,7 @@ dolunscan()
SCSISTR=
devnr="$host $channel $id $lun"
echo -e " Scanning for device $devnr ... "
- printf "${yellow}OLD: %s" "$norm"
+ printf "${yellow}OLD: %s ${norm}"
testexist
# Device exists: Test whether it's still online
# (testonline returns 2 if it's gone and 1 if it has changed)
@@ -552,10 +552,10 @@ dolunscan()
echo 1 > "$devpath/rescan"
fi
fi
- printf "\r\e[A\e[A\e[A${yellow}OLD: %s" "$norm"
+ printf "\r\e[A\e[A\e[A${yellow}OLD: %s ${norm}"
testexist
if [ -z "$SCSISTR" ] && [ $RC != 1 ] && [ "$remappedlun0" != "1" ] ; then
- printf "\r${red}DEL: %s\r\n\n" "$norm"
+ printf "\r${red}DEL: %s\r\n\n ${norm}"
# In the event we're replacing with a well known node, we need to let it continue, to create the replacement node
[ "$remappedlun0" != "2" ] && return 2
fi
@@ -563,7 +563,7 @@ dolunscan()
if [ -z "$SCSISTR" ] || [ -n "$remappedlun0" ] ; then
if [ "$remappedlun0" != "2" ] ; then
# Device does not exist, try to add
- printf "\r${green}NEW: %s" "$norm"
+ printf "\r${green}NEW: %s ${norm}"
fi
if [ -e "/sys/class/scsi_host/host${host}/scan" ] ; then
echo "$channel $id $lun" > "/sys/class/scsi_host/host${host}/scan" 2> /dev/null
@@ -595,12 +595,12 @@ doreportlun()
devnr="$host $channel $id $lun"
echo -en " Scanning for device $devnr ...\r"
lun0added=
- #printf "${yellow}OLD: %s" "$norm"
+ #printf "${yellow}OLD: %s ${norm}"
# Phase one: If LUN0 does not exist, try to add
testexist -q
if [ -z "$SCSISTR" ] ; then
# Device does not exist, try to add
- #printf "\r${green}NEW: %s" "$norm"
+ #printf "\r${green}NEW: %s ${norm}"
if [ -e "/sys/class/scsi_host/host${host}/scan" ] ; then
echo "$channel $id $lun" > "/sys/class/scsi_host/host${host}/scan" 2> /dev/null
udevadm_settle
@@ -831,7 +831,7 @@ findremapped()
if [ "$id_serial" = "1" ] || [ $remapped -eq 0 ] ; then
continue
fi
- printf "${yellow}REMAPPED: %s" "$norm"
+ printf "${yellow}REMAPPED: %s ${norm}"
host=$(echo "$hctl" | cut -d":" -f1)
channel=$(echo "$hctl" | cut -d":" -f2)
id=$(echo "$hctl" | cut -d":" -f3)
@@ -1079,7 +1079,7 @@ findresized()
new_size=$(cat "$sysfs_path/block/$sddev/size")
if [ "$size" != "$new_size" ] && [ "$size" != "0" ] && [ "$new_size" != "0" ] ; then
- printf "${yellow}RESIZED: %s" "$norm"
+ printf "${yellow}RESIZED: %s ${norm}"
host=$(echo "$hctl" | cut -d":" -f1)
channel=$(echo "$hctl" | cut -d":" -f2)
id=$(echo "$hctl" | cut -d":" -f3)
diff --git a/src/Makefile.am b/src/Makefile.am
index 676f61fa..034f171d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,9 +4,9 @@ bin_PROGRAMS = \
sg_get_config sg_get_elem_status sg_get_lba_status sg_ident sg_inq \
sg_logs sg_luns sg_modes sg_opcodes sg_persist sg_prevent sg_raw \
sg_rdac sg_read_attr sg_read_block_limits sg_read_buffer \
- sg_read_long sg_readcap sg_reassign sg_referrals sg_rep_density \
- sg_rep_pip sg_rep_zones sg_requests sg_reset_wp sg_rmsn sg_rtpg \
- sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \
+ sg_read_long sg_readcap sg_reassign sg_referrals sg_rem_rest_elem \
+ sg_rep_density sg_rep_pip sg_rep_zones sg_requests sg_reset_wp \
+ sg_rmsn sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \
sg_sat_read_gplog sg_sat_set_features sg_seek sg_senddiag sg_ses \
sg_ses_microcode sg_start sg_stpg sg_stream_ctl sg_sync sg_timestamp \
sg_turs sg_unmap sg_verify sg_vpd sg_wr_mode sg_write_buffer \
@@ -131,16 +131,18 @@ sg_read_long_LDADD = ../lib/libsgutils2.la
sg_reassign_LDADD = ../lib/libsgutils2.la
-sg_requests_LDADD = ../lib/libsgutils2.la
-
sg_referrals_LDADD = ../lib/libsgutils2.la
+sg_rem_rest_elem_LDADD = ../lib/libsgutils2.la
+
sg_rep_density_LDADD = ../lib/libsgutils2.la
sg_rep_pip_LDADD = ../lib/libsgutils2.la
sg_rep_zones_LDADD = ../lib/libsgutils2.la
+sg_requests_LDADD = ../lib/libsgutils2.la
+
sg_reset_wp_LDADD = ../lib/libsgutils2.la
sg_rmsn_LDADD = ../lib/libsgutils2.la
diff --git a/src/Makefile.in b/src/Makefile.in
index 8e7c9a7f..a71b2ca7 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -97,8 +97,9 @@ bin_PROGRAMS = sg_bg_ctl$(EXEEXT) sg_compare_and_write$(EXEEXT) \
sg_raw$(EXEEXT) sg_rdac$(EXEEXT) sg_read_attr$(EXEEXT) \
sg_read_block_limits$(EXEEXT) sg_read_buffer$(EXEEXT) \
sg_read_long$(EXEEXT) sg_readcap$(EXEEXT) sg_reassign$(EXEEXT) \
- sg_referrals$(EXEEXT) sg_rep_density$(EXEEXT) \
- sg_rep_pip$(EXEEXT) sg_rep_zones$(EXEEXT) sg_requests$(EXEEXT) \
+ sg_referrals$(EXEEXT) sg_rem_rest_elem$(EXEEXT) \
+ sg_rep_density$(EXEEXT) sg_rep_pip$(EXEEXT) \
+ sg_rep_zones$(EXEEXT) sg_requests$(EXEEXT) \
sg_reset_wp$(EXEEXT) sg_rmsn$(EXEEXT) sg_rtpg$(EXEEXT) \
sg_safte$(EXEEXT) sg_sanitize$(EXEEXT) \
sg_sat_identify$(EXEEXT) sg_sat_phy_event$(EXEEXT) \
@@ -246,6 +247,9 @@ sg_reassign_DEPENDENCIES = ../lib/libsgutils2.la
sg_referrals_SOURCES = sg_referrals.c
sg_referrals_OBJECTS = sg_referrals.$(OBJEXT)
sg_referrals_DEPENDENCIES = ../lib/libsgutils2.la
+sg_rem_rest_elem_SOURCES = sg_rem_rest_elem.c
+sg_rem_rest_elem_OBJECTS = sg_rem_rest_elem.$(OBJEXT)
+sg_rem_rest_elem_DEPENDENCIES = ../lib/libsgutils2.la
sg_rep_density_SOURCES = sg_rep_density.c
sg_rep_density_OBJECTS = sg_rep_density.$(OBJEXT)
sg_rep_density_DEPENDENCIES = ../lib/libsgutils2.la
@@ -408,13 +412,13 @@ am__depfiles_remade = ./$(DEPDIR)/sg_bg_ctl.Po \
./$(DEPDIR)/sg_read_block_limits.Po \
./$(DEPDIR)/sg_read_buffer.Po ./$(DEPDIR)/sg_read_long.Po \
./$(DEPDIR)/sg_readcap.Po ./$(DEPDIR)/sg_reassign.Po \
- ./$(DEPDIR)/sg_referrals.Po ./$(DEPDIR)/sg_rep_density.Po \
- ./$(DEPDIR)/sg_rep_pip.Po ./$(DEPDIR)/sg_rep_zones.Po \
- ./$(DEPDIR)/sg_requests.Po ./$(DEPDIR)/sg_reset.Po \
- ./$(DEPDIR)/sg_reset_wp.Po ./$(DEPDIR)/sg_rmsn.Po \
- ./$(DEPDIR)/sg_rtpg.Po ./$(DEPDIR)/sg_safte.Po \
- ./$(DEPDIR)/sg_sanitize.Po ./$(DEPDIR)/sg_sat_identify.Po \
- ./$(DEPDIR)/sg_sat_phy_event.Po \
+ ./$(DEPDIR)/sg_referrals.Po ./$(DEPDIR)/sg_rem_rest_elem.Po \
+ ./$(DEPDIR)/sg_rep_density.Po ./$(DEPDIR)/sg_rep_pip.Po \
+ ./$(DEPDIR)/sg_rep_zones.Po ./$(DEPDIR)/sg_requests.Po \
+ ./$(DEPDIR)/sg_reset.Po ./$(DEPDIR)/sg_reset_wp.Po \
+ ./$(DEPDIR)/sg_rmsn.Po ./$(DEPDIR)/sg_rtpg.Po \
+ ./$(DEPDIR)/sg_safte.Po ./$(DEPDIR)/sg_sanitize.Po \
+ ./$(DEPDIR)/sg_sat_identify.Po ./$(DEPDIR)/sg_sat_phy_event.Po \
./$(DEPDIR)/sg_sat_read_gplog.Po \
./$(DEPDIR)/sg_sat_set_features.Po \
./$(DEPDIR)/sg_scan_linux.Po ./$(DEPDIR)/sg_scan_win32.Po \
@@ -458,17 +462,18 @@ SOURCES = sg_bg_ctl.c sg_compare_and_write.c sg_copy_results.c sg_dd.c \
sg_map26.c sg_modes.c sg_opcodes.c sg_persist.c sg_prevent.c \
sg_raw.c sg_rbuf.c sg_rdac.c sg_read.c sg_read_attr.c \
sg_read_block_limits.c sg_read_buffer.c sg_read_long.c \
- sg_readcap.c sg_reassign.c sg_referrals.c sg_rep_density.c \
- sg_rep_pip.c sg_rep_zones.c sg_requests.c sg_reset.c \
- sg_reset_wp.c sg_rmsn.c sg_rtpg.c sg_safte.c sg_sanitize.c \
- sg_sat_identify.c sg_sat_phy_event.c sg_sat_read_gplog.c \
- sg_sat_set_features.c $(sg_scan_SOURCES) sg_seek.c \
- sg_senddiag.c sg_ses.c sg_ses_microcode.c sg_start.c sg_stpg.c \
- sg_stream_ctl.c sg_sync.c sg_test_rwbuf.c sg_timestamp.c \
- sg_turs.c sg_unmap.c sg_verify.c $(sg_vpd_SOURCES) \
- sg_wr_mode.c sg_write_buffer.c sg_write_long.c sg_write_same.c \
- sg_write_verify.c sg_write_x.c sg_xcopy.c sg_z_act_query.c \
- sg_zone.c sginfo.c sgm_dd.c sgp_dd.c
+ sg_readcap.c sg_reassign.c sg_referrals.c sg_rem_rest_elem.c \
+ sg_rep_density.c sg_rep_pip.c sg_rep_zones.c sg_requests.c \
+ sg_reset.c sg_reset_wp.c sg_rmsn.c sg_rtpg.c sg_safte.c \
+ sg_sanitize.c sg_sat_identify.c sg_sat_phy_event.c \
+ sg_sat_read_gplog.c sg_sat_set_features.c $(sg_scan_SOURCES) \
+ sg_seek.c sg_senddiag.c sg_ses.c sg_ses_microcode.c sg_start.c \
+ sg_stpg.c sg_stream_ctl.c sg_sync.c sg_test_rwbuf.c \
+ sg_timestamp.c sg_turs.c sg_unmap.c sg_verify.c \
+ $(sg_vpd_SOURCES) sg_wr_mode.c sg_write_buffer.c \
+ sg_write_long.c sg_write_same.c sg_write_verify.c sg_write_x.c \
+ sg_xcopy.c sg_z_act_query.c sg_zone.c sginfo.c sgm_dd.c \
+ sgp_dd.c
DIST_SOURCES = sg_bg_ctl.c sg_compare_and_write.c sg_copy_results.c \
sg_dd.c sg_decode_sense.c sg_emc_trespass.c sg_format.c \
sg_get_config.c sg_get_elem_status.c sg_get_lba_status.c \
@@ -476,17 +481,18 @@ DIST_SOURCES = sg_bg_ctl.c sg_compare_and_write.c sg_copy_results.c \
sg_map26.c sg_modes.c sg_opcodes.c sg_persist.c sg_prevent.c \
sg_raw.c sg_rbuf.c sg_rdac.c sg_read.c sg_read_attr.c \
sg_read_block_limits.c sg_read_buffer.c sg_read_long.c \
- sg_readcap.c sg_reassign.c sg_referrals.c sg_rep_density.c \
- sg_rep_pip.c sg_rep_zones.c sg_requests.c sg_reset.c \
- sg_reset_wp.c sg_rmsn.c sg_rtpg.c sg_safte.c sg_sanitize.c \
- sg_sat_identify.c sg_sat_phy_event.c sg_sat_read_gplog.c \
- sg_sat_set_features.c $(am__sg_scan_SOURCES_DIST) sg_seek.c \
- sg_senddiag.c sg_ses.c sg_ses_microcode.c sg_start.c sg_stpg.c \
- sg_stream_ctl.c sg_sync.c sg_test_rwbuf.c sg_timestamp.c \
- sg_turs.c sg_unmap.c sg_verify.c $(sg_vpd_SOURCES) \
- sg_wr_mode.c sg_write_buffer.c sg_write_long.c sg_write_same.c \
- sg_write_verify.c sg_write_x.c sg_xcopy.c sg_z_act_query.c \
- sg_zone.c sginfo.c sgm_dd.c sgp_dd.c
+ sg_readcap.c sg_reassign.c sg_referrals.c sg_rem_rest_elem.c \
+ sg_rep_density.c sg_rep_pip.c sg_rep_zones.c sg_requests.c \
+ sg_reset.c sg_reset_wp.c sg_rmsn.c sg_rtpg.c sg_safte.c \
+ sg_sanitize.c sg_sat_identify.c sg_sat_phy_event.c \
+ sg_sat_read_gplog.c sg_sat_set_features.c \
+ $(am__sg_scan_SOURCES_DIST) sg_seek.c sg_senddiag.c sg_ses.c \
+ sg_ses_microcode.c sg_start.c sg_stpg.c sg_stream_ctl.c \
+ sg_sync.c sg_test_rwbuf.c sg_timestamp.c sg_turs.c sg_unmap.c \
+ sg_verify.c $(sg_vpd_SOURCES) sg_wr_mode.c sg_write_buffer.c \
+ sg_write_long.c sg_write_same.c sg_write_verify.c sg_write_x.c \
+ sg_xcopy.c sg_z_act_query.c sg_zone.c sginfo.c sgm_dd.c \
+ sgp_dd.c
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -691,11 +697,12 @@ sg_read_block_limits_LDADD = ../lib/libsgutils2.la
sg_read_buffer_LDADD = ../lib/libsgutils2.la
sg_read_long_LDADD = ../lib/libsgutils2.la
sg_reassign_LDADD = ../lib/libsgutils2.la
-sg_requests_LDADD = ../lib/libsgutils2.la
sg_referrals_LDADD = ../lib/libsgutils2.la
+sg_rem_rest_elem_LDADD = ../lib/libsgutils2.la
sg_rep_density_LDADD = ../lib/libsgutils2.la
sg_rep_pip_LDADD = ../lib/libsgutils2.la
sg_rep_zones_LDADD = ../lib/libsgutils2.la
+sg_requests_LDADD = ../lib/libsgutils2.la
sg_reset_wp_LDADD = ../lib/libsgutils2.la
sg_rmsn_LDADD = ../lib/libsgutils2.la
sg_rtpg_LDADD = ../lib/libsgutils2.la
@@ -939,6 +946,10 @@ sg_referrals$(EXEEXT): $(sg_referrals_OBJECTS) $(sg_referrals_DEPENDENCIES) $(EX
@rm -f sg_referrals$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(sg_referrals_OBJECTS) $(sg_referrals_LDADD) $(LIBS)
+sg_rem_rest_elem$(EXEEXT): $(sg_rem_rest_elem_OBJECTS) $(sg_rem_rest_elem_DEPENDENCIES) $(EXTRA_sg_rem_rest_elem_DEPENDENCIES)
+ @rm -f sg_rem_rest_elem$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sg_rem_rest_elem_OBJECTS) $(sg_rem_rest_elem_LDADD) $(LIBS)
+
sg_rep_density$(EXEEXT): $(sg_rep_density_OBJECTS) $(sg_rep_density_DEPENDENCIES) $(EXTRA_sg_rep_density_DEPENDENCIES)
@rm -f sg_rep_density$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(sg_rep_density_OBJECTS) $(sg_rep_density_LDADD) $(LIBS)
@@ -1141,6 +1152,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_readcap.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_reassign.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_referrals.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rem_rest_elem.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rep_density.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rep_pip.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rep_zones.Po@am__quote@ # am--include-marker
@@ -1376,6 +1388,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/sg_readcap.Po
-rm -f ./$(DEPDIR)/sg_reassign.Po
-rm -f ./$(DEPDIR)/sg_referrals.Po
+ -rm -f ./$(DEPDIR)/sg_rem_rest_elem.Po
-rm -f ./$(DEPDIR)/sg_rep_density.Po
-rm -f ./$(DEPDIR)/sg_rep_pip.Po
-rm -f ./$(DEPDIR)/sg_rep_zones.Po
@@ -1496,6 +1509,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/sg_readcap.Po
-rm -f ./$(DEPDIR)/sg_reassign.Po
-rm -f ./$(DEPDIR)/sg_referrals.Po
+ -rm -f ./$(DEPDIR)/sg_rem_rest_elem.Po
-rm -f ./$(DEPDIR)/sg_rep_density.Po
-rm -f ./$(DEPDIR)/sg_rep_pip.Po
-rm -f ./$(DEPDIR)/sg_rep_zones.Po
diff --git a/src/sg_decode_sense.c b/src/sg_decode_sense.c
index 76e5f6f9..160544be 100644
--- a/src/sg_decode_sense.c
+++ b/src/sg_decode_sense.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2021 Douglas Gilbert.
+ * Copyright (c) 2010-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.
@@ -30,7 +30,9 @@
#include "sg_unaligned.h"
-static const char * version_str = "1.25 20211119";
+static const char * version_str = "1.27 20220624";
+
+#define MY_NAME "sg_decode_sense"
#define MAX_SENSE_LEN 4096 /* max descriptor format actually: 255+8 */
@@ -44,6 +46,7 @@ static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"hex", no_argument, 0, 'H'},
{"in", required_argument, 0, 'i'}, /* don't advertise */
+ {"json", optional_argument, 0, 'j'},
{"inhex", required_argument, 0, 'i'}, /* same as --file */
{"nodecode", no_argument, 0, 'N'},
{"nospace", no_argument, 0, 'n'},
@@ -73,6 +76,7 @@ struct opts_t {
int verbose;
const char * wfname;
const char * no_space_str;
+ sgj_state json_st;
uint8_t sense[MAX_SENSE_LEN + 4];
};
@@ -85,10 +89,10 @@ usage()
pr2serr("Usage: sg_decode_sense [--binary=BFN] [--cdb] [--err=ES] "
"[--file=HFN]\n"
" [--help] [--hex] [--inhex=HFN] "
- "[--nodecode]\n"
- " [--nospace] [--status=SS] [--verbose] "
- "[--version]\n"
- " [--write=WFN] H1 H2 H3 ...\n"
+ "[--json[=JO]]\n"
+ " [--nodecode] [--nospace] [--status=SS] "
+ "[--verbose]\n"
+ " [--version] [--write=WFN] H1 H2 H3 ...\n"
" where:\n"
" --binary=BFN|-b BFN BFN is a file name to read sense "
"data in\n"
@@ -106,8 +110,16 @@ usage()
" --hex|-H used together with --write=WFN, to "
"write out\n"
" C language style ASCII hex (instead "
- "of binary)\n"
+ "of binary).\n"
+ " Otherwise don't decode, output incoming "
+ "data in\n"
+ " hex (used '-HH' or '-HHH' for different "
+ "formats)\n"
" --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"
" --nodecode|-N do not decode, may be neither sense "
"nor cdb\n"
" --nospace|-n no spaces or other separators between "
@@ -138,7 +150,7 @@ parse_cmd_line(struct opts_t *op, int argc, char *argv[])
char *endptr;
while (1) {
- c = getopt_long(argc, argv, "b:ce:f:hHi:nNs:vVw:", long_options,
+ c = getopt_long(argc, argv, "b:ce:f:hHi:j::nNs:vVw:", long_options,
NULL);
if (c == -1)
break;
@@ -178,6 +190,9 @@ parse_cmd_line(struct opts_t *op, int argc, char *argv[])
case '?':
op->do_help = true;
return 0;
+ case 'H':
+ op->hex_count++;
+ break;
case 'i':
if (op->fname) {
pr2serr("expect only one '--binary=BFN', '--file=HFN' or "
@@ -187,8 +202,12 @@ parse_cmd_line(struct opts_t *op, int argc, char *argv[])
op->file_given = true;
op->fname = optarg;
break;
- case 'H':
- op->hex_count++;
+ 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);
+ return SG_LIB_SYNTAX_ERROR;
+ }
break;
case 'n':
op->no_space = true;
@@ -298,6 +317,7 @@ write2wfn(FILE * fp, struct opts_t * op)
int
main(int argc, char *argv[])
{
+ bool as_json;
int k, err, blen;
int ret = 0;
unsigned int ui;
@@ -305,6 +325,9 @@ main(int argc, char *argv[])
struct opts_t * op;
FILE * fp = NULL;
const char * cp;
+ sgj_state * jsp;
+ sgj_opaque_p jop = NULL;
+ sgj_opaque_p jo2p;
char b[2048];
struct opts_t opts;
@@ -341,6 +364,10 @@ main(int argc, char *argv[])
usage();
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->err_given) {
char d[128];
@@ -368,29 +395,35 @@ main(int argc, char *argv[])
isxdigit((uint8_t)cp[k + 1]); k += 2) {
if (1 != sscanf(cp + k, "%2x", &ui)) {
pr2serr("bad no_space hex string: %s\n", cp);
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto fini;
}
op->sense[op->sense_len++] = (uint8_t)ui;
}
}
if ((0 == op->sense_len) && (! op->do_binary) && (! op->file_given)) {
- if (op->do_status)
- return 0;
+ if (op->do_status) {
+ ret = 0;
+ goto fini;
+ }
pr2serr(">> Need sense/cdb/arbitrary data on the command line or "
"in a file\n\n");
usage();
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto fini;
}
if (op->sense_len && (op->do_binary || op->file_given)) {
pr2serr(">> Need sense data on command line or in a file, not "
"both\n\n");
- return SG_LIB_CONTRADICT;
+ ret = SG_LIB_CONTRADICT;
+ goto fini;
}
if (op->do_binary && op->file_given) {
pr2serr(">> Either a binary file or a ASCII hexadecimal, file not "
"both\n\n");
- return SG_LIB_CONTRADICT;
+ ret = SG_LIB_CONTRADICT;
+ goto fini;
}
if (op->do_binary) {
@@ -399,13 +432,15 @@ main(int argc, char *argv[])
err = errno;
pr2serr("unable to open file: %s: %s\n", op->fname,
safe_strerror(err));
- return sg_convert_errno(err);
+ ret = sg_convert_errno(err);
+ goto fini;
}
s = fread(op->sense, 1, MAX_SENSE_LEN, fp);
fclose(fp);
if (0 == s) {
pr2serr("read nothing from file: %s\n", op->fname);
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto fini;
}
op->sense_len = s;
} else if (op->file_given) {
@@ -413,7 +448,7 @@ main(int argc, char *argv[])
&op->sense_len, MAX_SENSE_LEN);
if (ret) {
pr2serr("unable to decode ASCII hex from file: %s\n", op->fname);
- return ret;
+ goto fini;
}
}
@@ -463,11 +498,39 @@ main(int argc, char *argv[])
sg_get_opcode_sa_name(opcode, sa, 0, blen, b);
printf("%s\n", b);
} else {
- sg_get_sense_str(NULL, op->sense, op->sense_len,
- op->verbose, blen, b);
+ if (as_json)
+ sgj_get_sense(jsp, jop, op->sense, op->sense_len);
+ else
+ sg_get_sense_str(NULL, op->sense, op->sense_len,
+ op->verbose, blen, b);
printf("%s\n", b);
}
}
fini:
+ if (as_json) {
+
+#if 0
+// <<<< testing
+// 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[] = {0x2, 0x1, 0x0, 0x14,
+// 0x41, 0x42, 0x43, 0x20, 0x20, 0x20, 0x20, 0x20,
+// 0x58, 0x59, 0x5a, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
+
+// 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};
+
+jo2p = sgj_new_named_object(jsp, jop, "designation_descriptor");
+sgj_get_designation_descriptor(jsp, jo2p, dd, sizeof(dd));
+// <<<< end of testing
+#endif
+
+ if (0 == op->hex_count)
+ sgj_pr2file(&op->json_st, NULL, ret, stdout);
+ sgj_finish(jsp);
+ }
return ret;
}
diff --git a/src/sg_format.c b/src/sg_format.c
index 6c963af2..8703b1d5 100644
--- a/src/sg_format.c
+++ b/src/sg_format.c
@@ -40,7 +40,7 @@
#include "sg_pr2serr.h"
#include "sg_pt.h"
-static const char * version_str = "1.66 20220211";
+static const char * version_str = "1.67 20220607";
#define RW_ERROR_RECOVERY_PAGE 1 /* can give alternate with --mode=MP */
@@ -58,17 +58,6 @@ static const char * version_str = "1.66 20220211";
true -> request sense */
#define MAX_BUFF_SZ 252
-#if defined(MSC_VER) || defined(__MINGW32__)
-#define HAVE_MS_SLEEP
-#endif
-
-#ifdef HAVE_MS_SLEEP
-#include <windows.h>
-#define sleep_for(seconds) Sleep( (seconds) * 1000)
-#else
-#define sleep_for(seconds) sleep(seconds)
-#endif
-
/* FORMAT UNIT (SBC) and FORMAT MEDIUM (SSC) share the same opcode */
#define SG_FORMAT_MEDIUM_CMD 0x4
#define SG_FORMAT_MEDIUM_CMDLEN 6
@@ -508,7 +497,7 @@ scsi_format_unit(int fd, const struct opts_t * op)
POLL_DURATION_SECS;
if (! op->poll_type) {
for(first = true; ; first = false) {
- sleep_for(poll_wait_secs);
+ sg_sleep_secs(poll_wait_secs);
progress = -1;
res = sg_ll_test_unit_ready_progress(fd, 0, &progress,
true, (vb > 1) ? (vb - 1) : 0);
@@ -537,7 +526,7 @@ scsi_format_unit(int fd, const struct opts_t * op)
return sg_convert_errno(ENOMEM);
}
for(first = true; ; first = false) {
- sleep_for(poll_wait_secs);
+ sg_sleep_secs(poll_wait_secs);
memset(reqSense, 0x0, MAX_BUFF_SZ);
res = sg_ll_request_sense(fd, false, reqSense,
MAX_BUFF_SZ, false,
@@ -629,7 +618,7 @@ scsi_format_medium(int fd, const struct opts_t * op)
}
if (! op->poll_type) {
for(first = true; ; first = false) {
- sleep_for(POLL_DURATION_SECS);
+ sg_sleep_secs(POLL_DURATION_SECS);
progress = -1;
res = sg_ll_test_unit_ready_progress(fd, 0, &progress,
true, (vb > 1) ? (vb - 1) : 0);
@@ -658,7 +647,7 @@ scsi_format_medium(int fd, const struct opts_t * op)
return sg_convert_errno(ENOMEM);
}
for(first = true; ; first = false) {
- sleep_for(POLL_DURATION_SECS);
+ sg_sleep_secs(POLL_DURATION_SECS);
memset(reqSense, 0x0, MAX_BUFF_SZ);
res = sg_ll_request_sense(fd, false, reqSense,
MAX_BUFF_SZ, false,
@@ -748,7 +737,7 @@ scsi_format_with_preset(int fd, const struct opts_t * op)
}
if (! op->poll_type) {
for(first = true; ; first = false) {
- sleep_for(POLL_DURATION_SECS);
+ sg_sleep_secs(POLL_DURATION_SECS);
progress = -1;
res = sg_ll_test_unit_ready_progress(fd, 0, &progress,
true, (vb > 1) ? (vb - 1) : 0);
@@ -777,7 +766,7 @@ scsi_format_with_preset(int fd, const struct opts_t * op)
return sg_convert_errno(ENOMEM);
}
for(first = true; ; first = false) {
- sleep_for(POLL_DURATION_SECS);
+ sg_sleep_secs(POLL_DURATION_SECS);
memset(reqSense, 0x0, MAX_BUFF_SZ);
res = sg_ll_request_sense(fd, false, reqSense,
MAX_BUFF_SZ, false,
@@ -1680,24 +1669,8 @@ again_sp_false:
if (op->format) {
format_only:
- if (op->quick)
- goto skip_f_unit_reconsider;
- printf("\nA FORMAT UNIT will commence in 15 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n",
- op->device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
- printf("\nA FORMAT UNIT will commence in 10 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n",
- op->device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
- printf("\nA FORMAT UNIT will commence in 5 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n",
- op->device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
-skip_f_unit_reconsider:
+ if (! op->quick)
+ sg_warn_and_wait("FORMAT UNIT", op->device_name, true);
res = scsi_format_unit(fd, op);
ret = res;
if (res) {
@@ -1712,24 +1685,8 @@ skip_f_unit_reconsider:
format_med:
if (! op->poll_type_given) /* SSC-5 specifies REQUEST SENSE polling */
op->poll_type = true;
- if (op->quick)
- goto skip_f_med_reconsider;
- printf("\nA FORMAT MEDIUM will commence in 15 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n",
- op->device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
- printf("\nA FORMAT MEDIUM will commence in 10 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n",
- op->device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
- printf("\nA FORMAT MEDIUM will commence in 5 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n",
- op->device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
-skip_f_med_reconsider:
+ if (! op->quick)
+ sg_warn_and_wait("FORMAT MEDIUM", op->device_name, true);
res = scsi_format_medium(fd, op);
ret = res;
if (res) {
@@ -1740,24 +1697,8 @@ skip_f_med_reconsider:
goto out;
format_with_pre:
- if (op->quick)
- goto skip_f_with_pre_reconsider;
- printf("\nA FORMAT WITH PRESET will commence in 15 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n",
- op->device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
- printf("\nA FORMAT WITH PRESET will commence in 10 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n",
- op->device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
- printf("\nA FORMAT WITH PRESET will commence in 5 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n",
- op->device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
-skip_f_with_pre_reconsider:
+ if (! op->quick)
+ sg_warn_and_wait("FORMAT WITH PRESET", op->device_name, true);
res = scsi_format_with_preset(fd, op);
ret = res;
if (res) {
diff --git a/src/sg_get_elem_status.c b/src/sg_get_elem_status.c
index 47e18a99..fc46608a 100644
--- a/src/sg_get_elem_status.c
+++ b/src/sg_get_elem_status.c
@@ -37,11 +37,10 @@
* given SCSI device.
*/
-static const char * version_str = "1.10 20220527"; /* sbc5r01 */
+static const char * version_str = "1.11 20220616"; /* sbc5r01 */
#define MY_NAME "sg_get_elem_status"
-
#ifndef UINT32_MAX
#define UINT32_MAX ((uint32_t)-1)
#endif
@@ -549,12 +548,12 @@ start_response:
goto fini;
}
- sgj_pr_twin_vi(jsp, jop, 0, "Number of descriptors",
- SGJ_SEP_COLON_1_SPACE, num_desc);
- sgj_pr_twin_vi(jsp, jop, 0, "Number of descriptors returned",
- SGJ_SEP_COLON_1_SPACE, num_desc_ret);
- sgj_pr_twin_vi(jsp, jop, 0, "Identifier of element being depopulated",
- SGJ_SEP_COLON_1_SPACE, id_elem_depop);
+ sgj_pr_hr_js_vi(jsp, jop, 0, "Number of descriptors",
+ SGJ_SEP_COLON_1_SPACE, num_desc);
+ sgj_pr_hr_js_vi(jsp, jop, 0, "Number of descriptors returned",
+ SGJ_SEP_COLON_1_SPACE, num_desc_ret);
+ sgj_pr_hr_js_vi(jsp, jop, 0, "Identifier of element being depopulated",
+ SGJ_SEP_COLON_1_SPACE, id_elem_depop);
if (rlen < 64) {
sgj_pr_hr(jsp, "No complete physical element status descriptors "
"available\n");
@@ -575,18 +574,18 @@ start_response:
decode_elem_status_desc(bp, &a_ped);
if (jsp->pr_as_json) {
jo2p = sgj_new_unattached_object(jsp);
- sgj_add_name_pair_ihex(jsp, jo2p, "element_identifier",
- (int64_t)a_ped.elem_id);
+ sgj_add_nv_ihex(jsp, jo2p, "element_identifier",
+ (int64_t)a_ped.elem_id);
cp = (1 == a_ped.phys_elem_type) ? "storage" : "reserved";
- sgj_add_name_pair_istr(jsp, jo2p, "physical_element_type",
- a_ped.phys_elem_type, "meaning", cp);
+ sgj_add_nv_istr(jsp, jo2p, "physical_element_type",
+ a_ped.phys_elem_type, "meaning", cp);
j = a_ped.phys_elem_health;
fetch_health_str(j, b, blen);
- sgj_add_name_pair_istr(jsp, jo2p, "physical_element_health", j,
- "meaning", b);
- sgj_add_name_pair_ihex(jsp, jo2p, "associated_capacity",
- (int64_t)a_ped.assoc_cap);
- sgj_add_val_o(jsp, jap, NULL /* name */, jo2p);
+ sgj_add_nv_istr(jsp, jo2p, "physical_element_health", j,
+ "meaning", b);
+ sgj_add_nv_ihex(jsp, jo2p, "associated_capacity",
+ (int64_t)a_ped.assoc_cap);
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
} else if (do_brief) {
sgj_pr_hr(jsp, "%u: %u,%u\n", a_ped.elem_id, a_ped.phys_elem_type,
a_ped.phys_elem_health);
diff --git a/src/sg_get_lba_status.c b/src/sg_get_lba_status.c
index 6a905793..1612aaac 100644
--- a/src/sg_get_lba_status.c
+++ b/src/sg_get_lba_status.c
@@ -35,14 +35,16 @@
* device.
*/
-static const char * version_str = "1.25 20220520"; /* sbc4r15 */
+static const char * version_str = "1.27 20220616"; /* sbc5r01 */
+
+#define MY_NAME "sg_get_lba_status"
#ifndef UINT32_MAX
#define UINT32_MAX ((uint32_t)-1)
#endif
#define MAX_GLBAS_BUFF_LEN (1024 * 1024)
-#define DEF_GLBAS_BUFF_LEN 24
+#define DEF_GLBAS_BUFF_LEN 1024
#define MIN_MAXLEN 16
static uint8_t glbasFixedBuff[DEF_GLBAS_BUFF_LEN];
@@ -52,12 +54,14 @@ static struct option long_options[] = {
{"16", no_argument, 0, 'S'},
{"32", no_argument, 0, 'T'},
{"brief", no_argument, 0, 'b'},
+ {"blockhex", no_argument, 0, 'B'},
{"element-id", required_argument, 0, 'e'},
{"element_id", required_argument, 0, 'e'},
{"help", no_argument, 0, 'h'},
{"hex", no_argument, 0, 'H'},
{"in", required_argument, 0, 'i'}, /* silent, same as --inhex= */
{"inhex", required_argument, 0, 'i'},
+ {"json", optional_argument, 0, 'j'},
{"lba", required_argument, 0, 'l'},
{"maxlen", required_argument, 0, 'm'},
{"raw", no_argument, 0, 'r'},
@@ -74,17 +78,20 @@ static struct option long_options[] = {
static void
usage()
{
- pr2serr("Usage: sg_get_lba_status [--16] [--32][--brief] "
- "[--element-id=EI]\n"
- " [--help] [--hex] [--inhex=FN] "
- "[--lba=LBA]\n"
- " [--maxlen=LEN] [--raw] [--readonly]\n"
+ pr2serr("Usage: sg_get_lba_status [--16] [--32] [--blockhex] "
+ "[--brief]\n"
+ " [--element-id=EI] [--help] [--hex] "
+ "[--inhex=FN]\n"
+ " [--lba=LBA] [--maxlen=LEN] [--raw] "
+ "[--readonly]\n"
" [--report-type=RT] [--scan-len=SL] "
"[--verbose]\n"
" [--version] DEVICE\n"
" where:\n"
" --16|-S use GET LBA STATUS(16) cdb (def)\n"
" --32|-T use GET LBA STATUS(32) cdb\n"
+ " --blockhex|-B outputs the (number of) blocks field "
+ " in hex\n"
" --brief|-b a descriptor per line:\n"
" <lba_hex blocks_hex p_status "
"add_status>\n"
@@ -98,6 +105,8 @@ usage()
"DEVICE,\n"
" assumed to be ASCII hex or, if --raw, "
"in binary\n"
+ " --json[=JO]|-j[JO] output in JSON instead of human "
+ "readable text\n"
" --lba=LBA|-l LBA starting LBA (logical block address) "
"(def: 0)\n"
" --maxlen=LEN|-m LEN max response length (allocation "
@@ -122,8 +131,10 @@ usage()
" --verbose|-v increase verbosity\n"
" --version|-V print version string and exit\n\n"
"Performs a SCSI GET LBA STATUS(16) or GET LBA STATUS(32) "
- "command (SBC-3 and\nSBC-4). If --inhex=FN is given then "
- "contents of FN is assumed to be a response\nto this command.\n"
+ "command (SBC-3 and\nSBC-4). The --element-id=EI and the "
+ "--scan-len=SL fields are only active\non the 32 byte cdb "
+ "variant. If --inhex=FN is given then contents of FN is\n"
+ "assumed to be a response to this command.\n"
);
}
@@ -159,6 +170,49 @@ decode_lba_status_desc(const uint8_t * bp, uint64_t * slbap,
return bp[12] & 0xf;
}
+static char *
+get_prov_status_str(int ps, char * b, int blen)
+{
+ switch (ps) {
+ case 0:
+ sg_scnpr(b, blen, "mapped (or unknown)");
+ break;
+ case 1:
+ sg_scnpr(b, blen, "deallocated");
+ break;
+ case 2:
+ sg_scnpr(b, blen, "anchored");
+ break;
+ case 3:
+ sg_scnpr(b, blen, "mapped"); /* sbc4r12 */
+ break;
+ case 4:
+ sg_scnpr(b, blen, "unknown"); /* sbc4r12 */
+ break;
+ default:
+ sg_scnpr(b, blen, "unknown provisioning status: %d", ps);
+ break;
+ }
+ return b;
+}
+
+static char *
+get_add_status_str(int as, char * b, int blen)
+{
+ switch (as) {
+ case 0:
+ sg_scnpr(b, blen, "%s", "");
+ break;
+ case 1:
+ sg_scnpr(b, blen, "may contain unrecovered errors");
+ break;
+ default:
+ sg_scnpr(b, blen, "unknown additional status: %d", as);
+ break;
+ }
+ return b;
+}
+
int
main(int argc, char * argv[])
@@ -170,8 +224,9 @@ main(int argc, char * argv[])
bool o_readonly = false;
bool verbose_given = false;
bool version_given = false;
- int k, j, res, c, rlen, num_descs, completion_cond, in_len;
+ int k, j, res, c, n, rlen, num_descs, completion_cond, in_len;
int sg_fd = -1;
+ int blockhex = 0;
int do_brief = 0;
int do_hex = 0;
int ret = 0;
@@ -190,12 +245,22 @@ main(int argc, char * argv[])
const uint8_t * bp;
uint8_t * glbasBuffp = glbasFixedBuff;
uint8_t * free_glbasBuffp = NULL;
+ sgj_opaque_p jop = NULL;
+ sgj_opaque_p jo2p = NULL;
+ sgj_opaque_p jap = NULL;
+ sgj_state json_st = {0};
+ sgj_state * jsp = &json_st;
+ char b[144];
+ static const size_t blen = sizeof(b);
+ static const char * prov_stat_s = "Provisoning status";
+ static const char * add_stat_s = "Additional status";
+ static const char * compl_cond_s = "Completion condition";
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "be:hi:Hl:m:rRs:St:TvV", long_options,
- &option_index);
+ c = getopt_long(argc, argv, "bBe:hi:j::Hl:m:rRs:St:TvV",
+ long_options, &option_index);
if (c == -1)
break;
@@ -203,6 +268,9 @@ main(int argc, char * argv[])
case 'b':
++do_brief;
break;
+ case 'B':
+ ++blockhex;
+ break;
case 'e':
ll = sg_get_llnum(optarg);
if ((ll < 0) || (ll > UINT32_MAX)) {
@@ -221,6 +289,13 @@ main(int argc, char * argv[])
case 'i':
in_fn = optarg;
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':
ll = sg_get_llnum(optarg);
if (-1 == ll) {
@@ -318,6 +393,8 @@ main(int argc, char * argv[])
pr2serr("version: %s\n", version_str);
return 0;
}
+ if (jsp->pr_as_json)
+ jop = sgj_start(MY_NAME, version_str, argc, argv, jsp);
if (maxlen > DEF_GLBAS_BUFF_LEN) {
glbasBuffp = (uint8_t *)sg_memalign(maxlen, 0, &free_glbasBuffp,
@@ -416,10 +493,10 @@ start_response:
goto fini;
}
if (do_hex) {
- if (do_hex > 2)
- hex2stdout(glbasBuffp, k, -1);
- else
- hex2stdout(glbasBuffp, k, (2 == do_hex) ? 0 : 1);
+ if (do_hex > 2)
+ hex2stdout(glbasBuffp, k, -1);
+ else
+ hex2stdout(glbasBuffp, k, (2 == do_hex) ? 0 : 1);
goto fini;
}
if (maxlen < 4) {
@@ -438,9 +515,9 @@ start_response:
rlen = maxlen;
if (do_brief > 1) {
- if (rlen < 24) {
- pr2serr("Need maxlen and response length to be at least 24, "
- "have %d bytes\n", rlen);
+ if (rlen > DEF_GLBAS_BUFF_LEN) {
+ pr2serr("Need maxlen and response length to be at least %d, "
+ "have %d bytes\n", DEF_GLBAS_BUFF_LEN, rlen);
ret = SG_LIB_CAT_OTHER;
goto fini;
}
@@ -462,92 +539,111 @@ start_response:
ret = SG_LIB_CAT_OTHER;
goto fini;
}
- printf("%d\n", res);
+ sgj_pr_hr(jsp,"p_status: %d add_status: 0x%x\n", res,
+ (unsigned int)add_status);
+ if (jsp->pr_as_json) {
+ sgj_add_nv_i(jsp, jop, prov_stat_s, res);
+ sgj_add_nv_i(jsp, jop, add_stat_s, add_status);
+ }
goto fini;
}
if (rlen < 24) {
- printf("No complete LBA status descriptors available\n");
+ sgj_pr_hr(jsp, "No complete LBA status descriptors available\n");
goto fini;
}
num_descs = (rlen - 8) / 16;
completion_cond = (*(glbasBuffp + 7) >> 1) & 7; /* added sbc4r14 */
if (do_brief)
- printf("Completion condition=%d\n", completion_cond);
+ sgj_pr_hr_js_vi(jsp, jop, 0, compl_cond_s,
+ SGJ_SEP_EQUAL_NO_SPACE, completion_cond);
else {
switch (completion_cond) {
case 0:
- printf("No indication of the completion condition\n");
+ snprintf(b, blen, "No indication of the completion condition");
break;
case 1:
- printf("Command completed due to meeting allocation length "
- "(--maxlen=LEN (def 24))\n");
+ snprintf(b, blen, "Command completed due to meeting allocation "
+ "length");
break;
case 2:
- printf("Command completed due to meeting scan length "
- "(--scan-len=SL)\n");
+ snprintf(b, blen, "Command completed due to meeting scan length");
break;
case 3:
- printf("Command completed due to meeting capacity of "
- "medium\n");
+ snprintf(b, blen, "Command completed due to meeting capacity of "
+ "medium");
break;
default:
- printf("Command completion is reserved [%d]\n",
+ snprintf(b, blen, "Command completion is reserved [%d]",
completion_cond);
break;
}
+ sgj_pr_hr(jsp, "%s\n", b);
+ sgj_add_nv_istr(jsp, jop, compl_cond_s, completion_cond,
+ NULL /* "meaning" */, b);
}
- printf("RTP=%d\n", *(glbasBuffp + 7) & 0x1); /* added sbc4r12 */
+ sgj_pr_hr_js_vi(jsp, jop, 0, "RTP", SGJ_SEP_EQUAL_NO_SPACE,
+ *(glbasBuffp + 7) & 0x1); /* added sbc4r12 */
if (verbose)
pr2serr("%d complete LBA status descriptors found\n", num_descs);
+ if (jsp->pr_as_json)
+ jap = sgj_new_named_array(jsp, jop, "lba_status_descriptor");
+
for (bp = glbasBuffp + 8, k = 0; k < num_descs; bp += 16, ++k) {
res = decode_lba_status_desc(bp, &d_lba, &d_blocks, &add_status);
if ((res < 0) || (res > 15))
pr2serr("descriptor %d: bad LBA status descriptor returned "
"%d\n", k + 1, res);
+ if (jsp->pr_as_json)
+ jo2p = sgj_new_unattached_object(jsp);
if (do_brief) {
- printf("0x");
+ n = 0;
+ n += sg_scnpr(b + n, blen - n, "0x");
for (j = 0; j < 8; ++j)
- printf("%02x", bp[j]);
- printf(" 0x%x %d %d\n", (unsigned int)d_blocks, res,
- add_status);
+ n += sg_scnpr(b + n, blen - n, "%02x", bp[j]);
+ if ((0 == blockhex) || (1 == (blockhex % 2)))
+ n += sg_scnpr(b + n, blen - n, " 0x%x %d %d",
+ (unsigned int)d_blocks, res, add_status);
+ else
+ n += sg_scnpr(b + n, blen - n, " %u %d %d",
+ (unsigned int)d_blocks, res, add_status);
+ sgj_pr_hr(jsp, "%s\n", b);
+ sgj_add_nv_ihex(jsp, jo2p, "lba", d_lba);
+ sgj_add_nv_ihex(jsp, jo2p, "blocks", d_blocks);
+ sgj_add_nv_i(jsp, jo2p, prov_stat_s, res);
+ sgj_add_nv_i(jsp, jo2p, add_stat_s, add_status);
} else {
- printf("[%d] LBA: 0x", k + 1);
- for (j = 0; j < 8; ++j)
- printf("%02x", bp[j]);
- printf(" blocks: %10u", (unsigned int)d_blocks);
- switch (res) {
- case 0:
- printf(" mapped (or unknown)");
- break;
- case 1:
- printf(" deallocated");
- break;
- case 2:
- printf(" anchored");
- break;
- case 3:
- printf(" mapped"); /* sbc4r12 */
- break;
- case 4:
- printf(" unknown"); /* sbc4r12 */
- break;
- default:
- printf(" Provisioning status: %d", res);
- break;
- }
- switch (add_status) {
- case 0:
- printf("\n");
- break;
- case 1:
- printf(" [may return unrecovered errors]\n");
- break;
- default:
- printf(" [add_status: 0x%x]\n", (unsigned int)add_status);
- break;
+ if (jsp->pr_as_json) {
+ sgj_add_nv_ihex(jsp, jo2p, "lba", d_lba);
+ sgj_add_nv_ihex(jsp, jo2p, "blocks", d_blocks);
+ sgj_add_nv_istr(jsp, jo2p, prov_stat_s, res, NULL,
+ get_prov_status_str(res, b, blen));
+ sgj_add_nv_istr(jsp, jo2p, add_stat_s, add_status, NULL,
+ get_add_status_str(add_status, b, blen));
+ } else {
+ char c[64];
+
+ n = 0;
+ n += sg_scnpr(b + n, blen - n, "[%d] LBA: 0x", k + 1);
+ for (j = 0; j < 8; ++j)
+ n += sg_scnpr(b + n, blen - n, "%02x", bp[j]);
+ if (1 == (blockhex % 2)) {
+
+ snprintf(c, sizeof(c), "0x%x", d_blocks);
+ n += sg_scnpr(b + n, blen - n, " blocks: %10s", c);
+ } else
+ n += sg_scnpr(b + n, blen - n, " blocks: %10u",
+ (unsigned int)d_blocks);
+ get_prov_status_str(res, c, sizeof(c));
+ n += sg_scnpr(b + n, blen - n, " %s", c);
+ get_add_status_str(add_status, c, sizeof(c));
+ if (strlen(c) > 0)
+ n += sg_scnpr(b + n, blen - n, " [%s]", c);
+ sgj_pr_hr(jsp, "%s\n", b);
}
}
+ if (jsp->pr_as_json)
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
}
if ((num_descs * 16) + 8 < rlen)
pr2serr("incomplete trailing LBA status descriptors found\n");
@@ -581,5 +677,11 @@ fini:
pr2serr("Some error occurred, try again with '-v' or '-vv' for "
"more information\n");
}
- return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+ ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+ if (jsp->pr_as_json) {
+ if (0 == do_hex)
+ sgj_pr2file(jsp, NULL, ret, stdout);
+ sgj_finish(jsp);
+ }
+ return ret;
}
diff --git a/src/sg_opcodes.c b/src/sg_opcodes.c
index 9d6f6c06..4eaa5bae 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.82 20220528"; /* spc6r06 */
+static const char * version_str = "0.83 20220616"; /* spc6r06 */
#define MY_NAME "sg_opcodes"
@@ -852,22 +852,22 @@ list_all_codes(uint8_t * rsoc_buff, int rsoc_len, struct opts_t * op,
}
if (jsp->pr_as_json) {
snprintf(b, blen, "0x%x", opcode);
- sgj_add_val_s(jsp, jop, "operation_code", b);
+ sgj_add_nv_s(jsp, jop, "operation_code", b);
if (sa_v) {
snprintf(b, blen, "0x%x", serv_act);
- sgj_add_val_s(jsp, jop, "service_action", b);
+ sgj_add_nv_s(jsp, jop, "service_action", b);
}
if (name_buff[0])
- sgj_add_val_s(jsp, jop, "name", name_buff);
- sgj_add_val_i(jsp, jop, "rwcdlp", (byt5 >> 6) & 0x1);
- sgj_add_val_i(jsp, jop, "mlu", (byt5 >> 4) & 0x3);
- sgj_add_val_i(jsp, jop, "cdlp", (byt5 >> 2) & 0x3);
- sgj_add_val_i(jsp, jop, "ctdp", (byt5 >> 1) & 0x1);
- sgj_add_val_i(jsp, jop, "servactv", byt5 & 0x1);
- sgj_add_val_i(jsp, jop, "cdb_length",
- sg_get_unaligned_be16(bp + 6));
-
- sgj_add_val_o(jsp, jap, NULL /* implies an array add */, jop);
+ sgj_add_nv_s(jsp, jop, "name", name_buff);
+ sgj_add_nv_i(jsp, jop, "rwcdlp", (byt5 >> 6) & 0x1);
+ sgj_add_nv_i(jsp, jop, "mlu", (byt5 >> 4) & 0x3);
+ sgj_add_nv_i(jsp, jop, "cdlp", (byt5 >> 2) & 0x3);
+ sgj_add_nv_i(jsp, jop, "ctdp", (byt5 >> 1) & 0x1);
+ sgj_add_nv_i(jsp, jop, "servactv", byt5 & 0x1);
+ sgj_add_nv_i(jsp, jop, "cdb_length",
+ sg_get_unaligned_be16(bp + 6));
+
+ sgj_add_nv_o(jsp, jap, NULL /* implies an array add */, jop);
}
if (op->do_mask && ptvp) {
@@ -903,8 +903,8 @@ list_all_codes(uint8_t * rsoc_buff, int rsoc_len, struct opts_t * op,
l = strlen(b2p);
if ((l > 0) && (' ' == b2p[l - 1]))
b2p[l - 1] = '\0';
- sgj_add_val_i(jsp, jo2p, "cdb_size", cdb_sz);
- sgj_add_val_s(jsp, jo2p, "cdb_usage_data", b2p);
+ sgj_add_nv_i(jsp, jo2p, "cdb_size", cdb_sz);
+ sgj_add_nv_s(jsp, jo2p, "cdb_usage_data", b2p);
}
}
} else
@@ -942,9 +942,9 @@ decode_cmd_timeout_desc(uint8_t * dp, int max_b_len, char * b,
else
snprintf(b, max_b_len, "nominal timeout: %u secs, ", timeout);
if (jsp->pr_as_json) {
- sgj_add_val_i(jsp, jsp->userp, "command_specific", dp[3]);
- sgj_add_val_i(jsp, jsp->userp,
- "nominal_command_processing_timeout", timeout);
+ sgj_add_nv_i(jsp, jsp->userp, "command_specific", dp[3]);
+ sgj_add_nv_i(jsp, jsp->userp, "nominal_command_processing_timeout",
+ timeout);
}
len = strlen(b);
max_b_len -= len;
@@ -955,8 +955,7 @@ decode_cmd_timeout_desc(uint8_t * dp, int max_b_len, char * b,
else
snprintf(b, max_b_len, "recommended timeout: %u secs", timeout);
if (jsp->pr_as_json)
- sgj_add_val_i(jsp, jsp->userp,
- "recommended_command_timeout", timeout);
+ sgj_add_nv_i(jsp, jsp->userp, "recommended_command_timeout", timeout);
return;
}
@@ -1072,25 +1071,25 @@ list_one(uint8_t * rsoc_buff, int cd_len, int rep_opts,
int l;
snprintf(b, blen, "0x%x", op->opcode);
- sgj_add_val_s(jsp, jop, "operation_code", b);
+ sgj_add_nv_s(jsp, jop, "operation_code", b);
if (rep_opts > 1) {
snprintf(b, blen, "0x%x", op->servact);
- sgj_add_val_s(jsp, jop, "service_action", b);
+ sgj_add_nv_s(jsp, jop, "service_action", b);
}
- sgj_add_val_i(jsp, jop, "rwcdlp", rwcdlp);
- sgj_add_val_i(jsp, jop, "ctdp", ctdp);
- sgj_add_val_i(jsp, jop, "mlu", mlu);
- sgj_add_val_i(jsp, jop, "cdlp", cdlp);
- sgj_add_val_i(jsp, jop, "support", support);
- sgj_add_val_s(jsp, jop, "support_str", cp);
- sgj_add_val_i(jsp, jop, "cdb_size", cd_len);
+ sgj_add_nv_i(jsp, jop, "rwcdlp", rwcdlp);
+ sgj_add_nv_i(jsp, jop, "ctdp", ctdp);
+ sgj_add_nv_i(jsp, jop, "mlu", mlu);
+ sgj_add_nv_i(jsp, jop, "cdlp", cdlp);
+ sgj_add_nv_i(jsp, jop, "support", support);
+ sgj_add_nv_s(jsp, jop, "support_str", cp);
+ sgj_add_nv_i(jsp, jop, "cdb_size", cd_len);
n = 0;
for (k = 0; k < cd_len; ++k)
n += sg_scnpr(b + n, blen - n, "%.2x ", rsoc_buff[k + 4]);
l = strlen(b);
if ((l > 0) && (' ' == b[l - 1]))
b[l - 1] = '\0';
- sgj_add_val_s(jsp, jop, "cdb_usage_data", b);
+ sgj_add_nv_s(jsp, jop, "cdb_usage_data", b);
}
if (ctdp) {
jsp->userp = sgj_new_named_object(jsp, jsp->basep,
@@ -1370,17 +1369,17 @@ start_response:
goto fini;
}
if (jsp->pr_as_json) {
- sgj_add_val_b(jsp, jop, "ats", rsoc_buff[0] & 0x80);
- sgj_add_val_b(jsp, jop, "atss", rsoc_buff[0] & 0x40);
- sgj_add_val_b(jsp, jop, "cacas", rsoc_buff[0] & 0x20);
- sgj_add_val_b(jsp, jop, "ctss", rsoc_buff[0] & 0x10);
- sgj_add_val_b(jsp, jop, "lurs", rsoc_buff[0] & 0x8);
- sgj_add_val_b(jsp, jop, "qts", rsoc_buff[0] & 0x4);
- sgj_add_val_b(jsp, jop, "trs", rsoc_buff[0] & 0x2);
- sgj_add_val_b(jsp, jop, "ws", rsoc_buff[0] & 0x1);
- sgj_add_val_b(jsp, jop, "qaes", rsoc_buff[1] & 0x4);
- sgj_add_val_b(jsp, jop, "qtss", rsoc_buff[1] & 0x2);
- sgj_add_val_b(jsp, jop, "itnrs", rsoc_buff[1] & 0x1);
+ sgj_add_nv_b(jsp, jop, "ats", rsoc_buff[0] & 0x80);
+ sgj_add_nv_b(jsp, jop, "atss", rsoc_buff[0] & 0x40);
+ sgj_add_nv_b(jsp, jop, "cacas", rsoc_buff[0] & 0x20);
+ sgj_add_nv_b(jsp, jop, "ctss", rsoc_buff[0] & 0x10);
+ sgj_add_nv_b(jsp, jop, "lurs", rsoc_buff[0] & 0x8);
+ sgj_add_nv_b(jsp, jop, "qts", rsoc_buff[0] & 0x4);
+ sgj_add_nv_b(jsp, jop, "trs", rsoc_buff[0] & 0x2);
+ sgj_add_nv_b(jsp, jop, "ws", rsoc_buff[0] & 0x1);
+ sgj_add_nv_b(jsp, jop, "qaes", rsoc_buff[1] & 0x4);
+ sgj_add_nv_b(jsp, jop, "qtss", rsoc_buff[1] & 0x2);
+ sgj_add_nv_b(jsp, jop, "itnrs", rsoc_buff[1] & 0x1);
if (! jsp->pr_output)
goto fini;
}
diff --git a/src/sg_rem_rest_elem.c b/src/sg_rem_rest_elem.c
new file mode 100644
index 00000000..46af7287
--- /dev/null
+++ b/src/sg_rem_rest_elem.c
@@ -0,0 +1,317 @@
+/*
+ * 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 <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "sg_lib.h"
+#include "sg_lib_data.h"
+#include "sg_pt.h"
+#include "sg_cmds_basic.h"
+#include "sg_unaligned.h"
+#include "sg_pr2serr.h"
+
+/* A utility program originally written for the Linux OS SCSI subsystem.
+ *
+ * This program issues one of the following SCSI commands:
+ * - REMOVE ELEMENT AND TRUNCATE
+ * - RESTORE ELEMENTS AND REBUILD
+ */
+
+static const char * version_str = "1.00 20220610";
+
+#define REMOVE_ELEM_SA 0x18
+#define RESTORE_ELEMS_SA 0x19
+
+#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
+#define DEF_PT_TIMEOUT 60 /* 60 seconds */
+
+
+static struct option long_options[] = {
+ {"capacity", required_argument, 0, 'c'},
+ {"element", required_argument, 0, 'e'},
+ {"help", no_argument, 0, 'h'},
+ {"quick", no_argument, 0, 'q'},
+ {"remove", no_argument, 0, 'r'},
+ {"restore", no_argument, 0, 'R'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+static const char * remove_cmd_s = "Remove element and truncate";
+static const char * restore_cmd_s = "Restore elements and rebuild";
+
+
+static void
+usage()
+{
+ pr2serr("Usage: "
+ "sg_rem_rest_elem [--capacity=RC] [--element=EID] [--help] "
+ "[--quick]\n"
+ " [--remove] [--restore] [--verbose] "
+ "[--version]\n"
+ " DEVICE\n");
+ pr2serr(" where:\n"
+ " --capacity=RC|-c RC RC is requested capacity (unit: "
+ "block; def: 0)\n"
+ " --element=EID|-e EID EID is the element identifier to "
+ "remove;\n"
+ " default is 0 which is an invalid "
+ "EID\n"
+ " --help|-h print out usage message\n"
+ " --quick|-q bypass 15 second warn and wait\n"
+ " --remove|-r issue REMOVE ELEMENT AND TRUNCATE "
+ "command\n"
+ " --restore|-R issue RESTORE ELEMENTS AND REBUILD "
+ "command\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n\n"
+ "Performs a SCSI REMOVE ELEMENT AND TRUNCATE or RESTORE "
+ "ELEMENTS AND\nREBUILD command. Either the --remove or "
+ "--restore option needs to be given.\n");
+}
+
+/* Return of 0 -> success, various SG_LIB_CAT_* positive values or -1 ->
+ * other errors */
+static int
+sg_ll_rem_rest_elem(int sg_fd, int sa, uint64_t req_cap, uint32_t e_id,
+ bool noisy, int verbose)
+{
+ int ret, res, sense_cat;
+ struct sg_pt_base * ptvp;
+ uint8_t sai16_cdb[16] =
+ {SG_SERVICE_ACTION_IN_16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0};
+ uint8_t sense_b[SENSE_BUFF_LEN] = {0};
+ const char * cmd_name;
+
+ sai16_cdb[1] = 0x1f & sa;
+ if (REMOVE_ELEM_SA == sa) {
+ sg_put_unaligned_be64(req_cap, sai16_cdb + 2);
+ sg_put_unaligned_be32(e_id, sai16_cdb + 10);
+ cmd_name = remove_cmd_s;
+ } else
+ cmd_name = restore_cmd_s;
+ if (verbose) {
+ char d[128];
+
+ pr2serr(" %s cdb: %s\n", cmd_name,
+ sg_get_command_str(sai16_cdb, 16, false, sizeof(d), d));
+ }
+
+ ptvp = construct_scsi_pt_obj();
+ if (NULL == ptvp) {
+ pr2serr("%s: out of memory\n", cmd_name);
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, sai16_cdb, sizeof(sai16_cdb));
+ set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
+ res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
+ ret = sg_cmds_process_resp(ptvp, cmd_name, res, noisy,
+ verbose, &sense_cat);
+ if (-1 == ret) {
+ if (get_scsi_pt_transport_err(ptvp))
+ ret = SG_LIB_TRANSPORT_ERROR;
+ else
+ ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
+ } else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = sense_cat;
+ break;
+ }
+ } else
+ ret = 0;
+ destruct_scsi_pt_obj(ptvp);
+ return ret;
+}
+
+
+int
+main(int argc, char * argv[])
+{
+ bool quick = false;
+ bool reat = false;
+ bool resar = false;
+ bool verbose_given = false;
+ bool version_given = false;
+ int res, c;
+ int sg_fd = -1;
+ int verbose = 0;
+ int ret = 0;
+ int sa = 0;
+ uint32_t e_id = 0;
+ uint64_t req_cap = 0;
+ int64_t ll;
+ const char * device_name = NULL;
+ const char * cmd_name;
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "c:e:hqrRvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'c':
+ ll = sg_get_llnum(optarg);
+ if (-1 == ll) {
+ pr2serr("--capacity= expects a numeric argument\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ req_cap = (uint64_t)ll;
+ break;
+ case 'e':
+ ll = sg_get_llnum(optarg);
+ if ((ll < 0) || (ll > UINT32_MAX)) {
+ pr2serr("bad argument to '--element=EID'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (0 == ll)
+ pr2serr("Warning: 0 is an invalid element identifier\n");
+ e_id = (uint64_t)ll;
+ break;
+ case 'h':
+ case '?':
+ usage();
+ return 0;
+ case 'q':
+ quick = true;
+ break;
+ case 'r':
+ reat = true;
+ sa = REMOVE_ELEM_SA;
+ break;
+ case 'R':
+ resar = true;
+ sa = RESTORE_ELEMS_SA;
+ break;
+ case 'v':
+ verbose_given = true;
+ ++verbose;
+ break;
+ case 'V':
+ version_given = true;
+ break;
+ default:
+ pr2serr("unrecognised option code 0x%x ??\n", c);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (optind < argc) {
+ if (NULL == device_name) {
+ device_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ pr2serr("Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+
+#ifdef DEBUG
+ pr2serr("In DEBUG mode, ");
+ if (verbose_given && version_given) {
+ pr2serr("but override: '-vV' given, zero verbose and continue\n");
+ verbose_given = false;
+ version_given = false;
+ verbose = 0;
+ } else if (! verbose_given) {
+ pr2serr("set '-vv'\n");
+ verbose = 2;
+ } else
+ pr2serr("keep verbose=%d\n", verbose);
+#else
+ if (verbose_given && version_given)
+ pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
+#endif
+ if (version_given) {
+ pr2serr("version: %s\n", version_str);
+ return 0;
+ }
+
+ if (1 != ((int)reat + (int)resar)) {
+ pr2serr("One, and only one, of these options needs to be given:\n"
+ " --remove or --restore\n\n");
+ usage();
+ return SG_LIB_CONTRADICT;
+ }
+ cmd_name = reat ? remove_cmd_s : restore_cmd_s;
+
+ if (NULL == device_name) {
+ pr2serr("missing device name!\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
+ sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose);
+ if (sg_fd < 0) {
+ int err = -sg_fd;
+ if (verbose)
+ pr2serr("open error: %s: %s\n", device_name,
+ safe_strerror(err));
+ ret = sg_convert_errno(err);
+ goto fini;
+ }
+ if (! quick)
+ sg_warn_and_wait(cmd_name, device_name, false);
+
+ res = sg_ll_rem_rest_elem(sg_fd, sa, req_cap, e_id, true, verbose);
+ ret = res;
+ if (res) {
+ if (SG_LIB_CAT_INVALID_OP == res)
+ pr2serr("%s command not supported\n", cmd_name);
+ else {
+ char b[80];
+
+ sg_get_category_sense_str(res, sizeof(b), b, verbose);
+ pr2serr("%s command: %s\n", cmd_name, b);
+ }
+ }
+
+fini:
+ if (sg_fd >= 0) {
+ res = sg_cmds_close_device(sg_fd);
+ if (res < 0) {
+ pr2serr("close error: %s\n", safe_strerror(-res));
+ if (0 == ret)
+ ret = sg_convert_errno(-res);
+ }
+ }
+ if (0 == verbose) {
+ if (! sg_if_can2stderr("sg_rem_rest_elem failed: ", ret))
+ pr2serr("Some error occurred, try again with '-v' or '-vv' for "
+ "more information\n");
+ }
+ return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+}
diff --git a/src/sg_rep_zones.c b/src/sg_rep_zones.c
index 0866cd8d..a8d4cbc9 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.38 20220511";
+static const char * version_str = "1.39 20220616";
#define MY_NAME "sg_rep_zones"
@@ -395,28 +395,28 @@ prt_a_zn_desc(const uint8_t *bp, const struct opts_t * op,
zc = (bp[1] >> 4) & 0xf;
sg_get_zone_type_str(zt, sizeof(b), b);
sgj_pr_hr(jsp, " Zone type: %s\n", b);
- sgj_add_name_pair_istr(jsp, jop, "zone_type", zt, meaning_s, b);
+ sgj_add_nv_istr(jsp, jop, "zone_type", zt, meaning_s, b);
zone_condition_str(zc, b, sizeof(b), op->vb);
sgj_pr_hr(jsp, " Zone condition: %s\n", b);
- sgj_add_name_pair_istr(jsp, jop, "zone_condition", zc, meaning_s, b);
- sgj_pr_twin_vi(jsp, jop, 3, "PUEP", SGJ_SEP_COLON_1_SPACE,
- !!(bp[1] & 0x4));
- sgj_pr_twin_vi(jsp, jop, 3, "NON_SEQ", SGJ_SEP_COLON_1_SPACE,
- !!(bp[1] & 0x2));
- sgj_pr_twin_vi(jsp, jop, 3, "RESET", SGJ_SEP_COLON_1_SPACE,
- !!(bp[1] & 0x1));
+ sgj_add_nv_istr(jsp, jop, "zone_condition", zc, meaning_s, b);
+ sgj_pr_hr_js_vi(jsp, jop, 3, "PUEP", SGJ_SEP_COLON_1_SPACE,
+ !!(bp[1] & 0x4));
+ sgj_pr_hr_js_vi(jsp, jop, 3, "NON_SEQ", SGJ_SEP_COLON_1_SPACE,
+ !!(bp[1] & 0x2));
+ sgj_pr_hr_js_vi(jsp, jop, 3, "RESET", SGJ_SEP_COLON_1_SPACE,
+ !!(bp[1] & 0x1));
len = sg_get_unaligned_be64(bp + 8);
sgj_pr_hr(jsp, " Zone Length: 0x%" PRIx64 "\n", len);
- sgj_add_name_pair_ihex(jsp, jop, "zone_length", (int64_t)len);
+ sgj_add_nv_ihex(jsp, jop, "zone_length", (int64_t)len);
lba = sg_get_unaligned_be64(bp + 16);
sgj_pr_hr(jsp, " Zone start LBA: 0x%" PRIx64 "\n", lba);
- sgj_add_name_pair_ihex(jsp, jop, "zone_start_lba", (int64_t)lba);
+ sgj_add_nv_ihex(jsp, jop, "zone_start_lba", (int64_t)lba);
wp = sg_get_unaligned_be64(bp + 24);
if (sg_all_ffs((const uint8_t *)&wp, sizeof(wp)))
sgj_pr_hr(jsp, " Write pointer LBA: -1\n");
else
sgj_pr_hr(jsp, " Write pointer LBA: 0x%" PRIx64 "\n", wp);
- sgj_add_name_pair_ihex(jsp, jop, "write_pointer_lba", (int64_t)wp);
+ sgj_add_nv_ihex(jsp, jop, "write_pointer_lba", (int64_t)wp);
return lba + len;
}
@@ -457,12 +457,12 @@ decode_rep_zones(const uint8_t * rzBuff, int act_len, uint32_t decod_len,
"granularity";
sgj_pr_hr(jsp, " Same=%d: %s\n", same, same_desc_arr[same]);
- sgj_add_name_pair_istr(jsp, jop, "same", same, meaning_s,
- same_desc_arr[same]);
+ sgj_add_nv_istr(jsp, jop, "same", same, meaning_s,
+ same_desc_arr[same]);
sgj_pr_hr(jsp, " Maximum LBA: 0x%" PRIx64 "\n\n", mx_lba);
- sgj_add_name_pair_ihex(jsp, jop, "maximum_lba", mx_lba);
+ sgj_add_nv_ihex(jsp, jop, "maximum_lba", mx_lba);
sgj_pr_hr(jsp, " %s: 0x%" PRIx64 "\n\n", rzslbag_s, rzslbag);
- sgj_add_name_pair_ihex(jsp, jop, rzslbag_s, rzslbag);
+ sgj_add_nv_ihex(jsp, jop, rzslbag_s, rzslbag);
}
if (op->do_num > 0)
num_zd = (num_zd > op->do_num) ? op->do_num : num_zd;
@@ -483,7 +483,7 @@ decode_rep_zones(const uint8_t * rzBuff, int act_len, uint32_t decod_len,
}
sgj_pr_hr(jsp, "From last descriptor in this response:\n");
sgj_pr_hr(jsp, " %s%d\n", zn_dnum_s, num_zd - 1);
- sgj_add_val_i(jsp, jop, "zone_descriptor_index", num_zd - 1);
+ sgj_add_nv_i(jsp, jop, "zone_descriptor_index", num_zd - 1);
ul = prt_a_zn_desc(bp, op, jsp, jop);
if (ul > mx_lba)
sgj_pr_hr(jsp, " >> This zone seems to be the last one\n");
@@ -514,15 +514,14 @@ decode_rep_zones(const uint8_t * rzBuff, int act_len, uint32_t decod_len,
else
sgj_pr_hr(jsp, "0x%" PRIx64 "\n", wp);
jo2p = sgj_new_unattached_object(jsp);
- sgj_add_name_pair_ihex(jsp, jo2p, "write_pointer_lba",
- (int64_t)wp);
- sgj_add_val_o(jsp, jap, NULL /* name */, jo2p);
+ sgj_add_nv_ihex(jsp, jo2p, "write_pointer_lba", (int64_t)wp);
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
}
continue;
}
jo2p = sgj_new_unattached_object(jsp);
prt_a_zn_desc(bp, op, jsp, jo2p);
- sgj_add_val_o(jsp, jap, NULL /* name */, jo2p);
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
}
if ((op->do_num == 0) && (! op->wp_only) && (! op->do_hex)) {
if ((64 + (REPORT_ZONES_DESC_LEN * (uint32_t)num_zd)) < decod_len)
@@ -554,12 +553,12 @@ decode_rep_realms(const uint8_t * rzBuff, int act_len,
nr_locator = sg_get_unaligned_be64(rzBuff + 12);
else
nr_locator = 0;
- sgj_pr_twin_vi(jsp, jop, 0, "Realms_count", SGJ_SEP_EQUAL_NO_SPACE,
- realms_count);
- sgj_pr_twin_vi(jsp, jop, 0, "Realms_descriptor_length",
- SGJ_SEP_EQUAL_NO_SPACE, r_desc_len);
+ sgj_pr_hr_js_vi(jsp, jop, 0, "Realms_count", SGJ_SEP_EQUAL_NO_SPACE,
+ realms_count);
+ sgj_pr_hr_js_vi(jsp, jop, 0, "Realms_descriptor_length",
+ SGJ_SEP_EQUAL_NO_SPACE, r_desc_len);
sgj_pr_hr(jsp, "Next_realm_locator=0x%" PRIx64 "\n", nr_locator);
- sgj_add_name_pair_ihex(jsp, jop, "Next_realm_locator", nr_locator);
+ sgj_add_nv_ihex(jsp, jop, "Next_realm_locator", nr_locator);
if ((realms_count < 1) || (act_len < (64 + 16)) || (r_desc_len < 16)) {
if (op->vb) {
pr2serr("%s: exiting early because ", __func__);
@@ -598,17 +597,17 @@ decode_rep_realms(const uint8_t * rzBuff, int act_len,
sgj_opaque_p jo2p;
jo2p = sgj_new_unattached_object(jsp);
- sgj_pr_twin_vi(jsp, jo2p, 1, "Realms_id", SGJ_SEP_EQUAL_NO_SPACE,
- sg_get_unaligned_be32(bp + 0));
+ sgj_pr_hr_js_vi(jsp, jo2p, 1, "Realms_id", SGJ_SEP_EQUAL_NO_SPACE,
+ sg_get_unaligned_be32(bp + 0));
if (op->do_hex) {
hex2stdout(bp, r_desc_len, -1);
continue;
}
restrictions = sg_get_unaligned_be16(bp + 4);
sgj_pr_hr(jsp, " realm_restrictions=0x%hu\n", restrictions);
- sgj_add_name_pair_ihex(jsp, jo2p, "realm_restrictions", restrictions);
- sgj_pr_twin_vi(jsp, jo2p, 3, "active_zone_domain_id",
- SGJ_SEP_EQUAL_NO_SPACE, bp[7]);
+ sgj_add_nv_ihex(jsp, jo2p, "realm_restrictions", restrictions);
+ sgj_pr_hr_js_vi(jsp, jo2p, 3, "active_zone_domain_id",
+ SGJ_SEP_EQUAL_NO_SPACE, bp[7]);
ja2p = sgj_new_named_array(jsp, jo2p,
"realm_start_end_descriptors_list");
@@ -618,18 +617,16 @@ decode_rep_realms(const uint8_t * rzBuff, int act_len,
jo3p = sgj_new_unattached_object(jsp);
sgj_pr_hr(jsp, " zone_domain=%u\n", j);
- sgj_add_val_i(jsp, jo3p, "corresponding_zone_domain_id", j);
+ sgj_add_nv_i(jsp, jo3p, "corresponding_zone_domain_id", j);
lba = sg_get_unaligned_be64(zp + 0);
sgj_pr_hr(jsp, " starting_lba=0x%" PRIx64 "\n", lba);
- sgj_add_name_pair_ihex(jsp, jo3p, "realm_starting_lba",
- (int64_t)lba);
+ sgj_add_nv_ihex(jsp, jo3p, "realm_starting_lba", (int64_t)lba);
lba = sg_get_unaligned_be64(zp + 8);
sgj_pr_hr(jsp, " ending_lba=0x%" PRIx64 "\n", lba);
- sgj_add_name_pair_ihex(jsp, jo3p, "realm_ending_lba",
- (int64_t)lba);
- sgj_add_val_o(jsp, ja2p, NULL /* name */, jo3p);
+ sgj_add_nv_ihex(jsp, jo3p, "realm_ending_lba", (int64_t)lba);
+ sgj_add_nv_o(jsp, ja2p, NULL /* name */, jo3p);
}
- sgj_add_val_o(jsp, jap, NULL /* name */, jo2p);
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
}
return 0;
}
@@ -658,16 +655,16 @@ decode_rep_zdomains(const uint8_t * rzBuff, int act_len,
zd_locator = sg_get_unaligned_be64(rzBuff + 16);
else
zd_locator = 0;
- sgj_pr_twin_vi(jsp, jop, 0, "Zone_domains_returned_list_length=",
- SGJ_SEP_EQUAL_NO_SPACE, zd_ret_len);
- sgj_pr_twin_vi(jsp, jop, 0, "Zone_domains_supported",
- SGJ_SEP_EQUAL_NO_SPACE, zdoms_sup);
- sgj_pr_twin_vi(jsp, jop, 0, "Zone_domains_reported",
- SGJ_SEP_EQUAL_NO_SPACE, zdoms_rep);
+ sgj_pr_hr_js_vi(jsp, jop, 0, "Zone_domains_returned_list_length=",
+ SGJ_SEP_EQUAL_NO_SPACE, zd_ret_len);
+ sgj_pr_hr_js_vi(jsp, jop, 0, "Zone_domains_supported",
+ SGJ_SEP_EQUAL_NO_SPACE, zdoms_sup);
+ sgj_pr_hr_js_vi(jsp, jop, 0, "Zone_domains_reported",
+ SGJ_SEP_EQUAL_NO_SPACE, zdoms_rep);
sgj_pr_hr(jsp, "Reporting_options=0x%x\n", zd_rep_opts);
- sgj_add_name_pair_ihex(jsp, jop, "Reporting_options", zd_rep_opts);
+ sgj_add_nv_ihex(jsp, jop, "Reporting_options", zd_rep_opts);
sgj_pr_hr(jsp, "Zone_domain_locator=0x%" PRIx64 "\n", zd_locator);
- sgj_add_name_pair_ihex(jsp, jop, "Zone_domain_locator", zd_locator);
+ sgj_add_nv_ihex(jsp, jop, "Zone_domain_locator", zd_locator);
der_zdoms = zd_len / 96;
if (op->vb > 1)
@@ -680,24 +677,24 @@ decode_rep_zdomains(const uint8_t * rzBuff, int act_len,
sgj_opaque_p jo2p;
jo2p = sgj_new_unattached_object(jsp);
- sgj_pr_twin_vi(jsp, jo2p, 3, "zone_domain",
- SGJ_SEP_EQUAL_NO_SPACE, bp[0]);
+ sgj_pr_hr_js_vi(jsp, jo2p, 3, "zone_domain",
+ SGJ_SEP_EQUAL_NO_SPACE, bp[0]);
lba = sg_get_unaligned_be64(bp + 16);
sgj_pr_hr(jsp, " zone_count=%" PRIu64 "\n", lba);
- sgj_add_name_pair_ihex(jsp, jo2p, "zone_count", lba);
+ sgj_add_nv_ihex(jsp, jo2p, "zone_count", lba);
lba = sg_get_unaligned_be64(bp + 24);
sgj_pr_hr(jsp, " starting_lba=0x%" PRIx64 "\n", lba);
- sgj_add_name_pair_ihex(jsp, jo2p, "starting_lba", lba);
+ sgj_add_nv_ihex(jsp, jo2p, "starting_lba", lba);
lba = sg_get_unaligned_be64(bp + 32);
sgj_pr_hr(jsp, " ending_lba=0x%" PRIx64 "\n", lba);
- sgj_add_name_pair_ihex(jsp, jo2p, "ending_lba", lba);
+ sgj_add_nv_ihex(jsp, jo2p, "ending_lba", lba);
sgj_pr_hr(jsp, " zone_domain_zone_type=0x%x\n", bp[40]);
- sgj_add_name_pair_ihex(jsp, jo2p, "zone_domain_zone_type", bp[40]);
- sgj_pr_twin_vi(jsp, jo2p, 5, "VZDZT", SGJ_SEP_EQUAL_NO_SPACE,
- !!(0x2 & bp[42]));
- sgj_pr_twin_vi(jsp, jo2p, 5, "SRB", SGJ_SEP_EQUAL_NO_SPACE,
- !!(0x1 & bp[42]));
- sgj_add_val_o(jsp, jap, NULL /* name */, jo2p);
+ sgj_add_nv_ihex(jsp, jo2p, "zone_domain_zone_type", bp[40]);
+ sgj_pr_hr_js_vi(jsp, jo2p, 5, "VZDZT", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(0x2 & bp[42]));
+ sgj_pr_hr_js_vi(jsp, jo2p, 5, "SRB", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(0x1 & bp[42]));
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
}
return 0;
}
@@ -774,8 +771,8 @@ find_report_zones(int sg_fd, uint8_t * rzBuff, const char * cmd_name,
} else {
sgj_pr_hr(jsp, "Condition met at:\n");
sgj_pr_hr(jsp, " %s: %d\n", zn_dnum_s, zn_dnum);
- sgj_add_val_b(jsp, jo2p, "met", true);
- sgj_add_val_i(jsp, jo2p, "zone_descriptor_index", zn_dnum);
+ sgj_add_nv_b(jsp, jo2p, "met", true);
+ sgj_add_nv_i(jsp, jo2p, "zone_descriptor_index", zn_dnum);
prt_a_zn_desc(bp, op, jsp, jo2p);
}
} else {
@@ -783,8 +780,8 @@ find_report_zones(int sg_fd, uint8_t * rzBuff, const char * cmd_name,
memset(b, 0xff, 64);
hex2stdout((const uint8_t *)b, 64, -1);
} else {
- sgj_add_val_b(jsp, jo2p, "met", false);
- sgj_add_val_i(jsp, jo2p, "zone_descriptor_index", zn_dnum);
+ sgj_add_nv_b(jsp, jo2p, "met", false);
+ sgj_add_nv_i(jsp, jo2p, "zone_descriptor_index", zn_dnum);
if (num_rem < 1)
sgj_pr_hr(jsp, "Condition NOT met, checked %d zones; "
"next %s%u\n", op->do_num, zn_dnum_s, zn_dnum);
@@ -1340,7 +1337,7 @@ main(int argc, char * argv[])
else if (op->do_realms)
cmd_name = "Report realms";
if (as_json)
- sgj_add_val_s(jsp, jop, "scsi_command_name", cmd_name);
+ sgj_add_nv_s(jsp, jop, "scsi_command_name", cmd_name);
if ((op->serv_act != REPORT_ZONES_SA) && op->do_partial) {
pr2serr("Can only use --partial with REPORT ZONES\n");
return SG_LIB_SYNTAX_ERROR;
diff --git a/src/sg_requests.c b/src/sg_requests.c
index ee0c0388..903c7ce8 100644
--- a/src/sg_requests.c
+++ b/src/sg_requests.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2021 Douglas Gilbert.
+ * Copyright (c) 2004-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.
@@ -34,7 +34,7 @@
* This program issues the SCSI command REQUEST SENSE to the given SCSI device.
*/
-static const char * version_str = "1.39 20211114";
+static const char * version_str = "1.40 20220607";
#define MAX_REQS_RESP_LEN 255
#define DEF_REQS_RESP_LEN 252
@@ -45,17 +45,6 @@ static const char * version_str = "1.39 20211114";
#define REQUEST_SENSE_CMD 0x3
#define REQUEST_SENSE_CMDLEN 6
-/* Not all environments support the Unix sleep() */
-#if defined(MSC_VER) || defined(__MINGW32__)
-#define HAVE_MS_SLEEP
-#endif
-#ifdef HAVE_MS_SLEEP
-#include <windows.h>
-#define sleep_for(seconds) Sleep( (seconds) * 1000)
-#else
-#define sleep_for(seconds) sleep(seconds)
-#endif
-
#define ME "sg_requests: "
@@ -309,7 +298,7 @@ main(int argc, char * argv[])
for (k = 0; k < num_rs; ++k) {
act_din_len = 0;
if (k > 0)
- sleep_for(30);
+ sg_sleep_secs(30);
set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
memset(rsBuff, 0x0, sizeof(rsBuff));
diff --git a/src/sg_sanitize.c b/src/sg_sanitize.c
index 41db4bba..74c33f2f 100644
--- a/src/sg_sanitize.c
+++ b/src/sg_sanitize.c
@@ -33,19 +33,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.18 20220127";
-
-/* Not all environments support the Unix sleep() */
-#if defined(MSC_VER) || defined(__MINGW32__)
-#define HAVE_MS_SLEEP
-#endif
-#ifdef HAVE_MS_SLEEP
-#include <windows.h>
-#define sleep_for(seconds) Sleep( (seconds) * 1000)
-#else
-#define sleep_for(seconds) sleep(seconds)
-#endif
-
+static const char * version_str = "1.19 20220608";
#define ME "sg_sanitize: "
@@ -720,20 +708,8 @@ main(int argc, char * argv[])
sg_put_unaligned_be16((uint16_t)op->ipl, wBuff + 2);
}
- if ((! op->quick) && (! op->fail)) {
- printf("\nA SANITIZE will commence in 15 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n", device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
- printf("\nA SANITIZE will commence in 10 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n", device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
- printf("\nA SANITIZE will commence in 5 seconds\n");
- printf(" ALL data on %s will be DESTROYED\n", device_name);
- printf(" Press control-C to abort\n");
- sleep_for(5);
- }
+ if ((! op->quick) && (! op->fail))
+ sg_warn_and_wait("SANITIZE", device_name, true);
ret = do_sanitize(sg_fd, op, wBuff, param_lst_len);
if (ret) {
@@ -747,7 +723,7 @@ main(int argc, char * argv[])
pr2serr("Due to --dry-run option, leave poll loop\n");
break;
}
- sleep_for(POLL_DURATION_SECS);
+ sg_sleep_secs(POLL_DURATION_SECS);
memset(rsBuff, 0x0, sizeof(rsBuff));
res = sg_ll_request_sense(sg_fd, op->desc, rsBuff, sizeof(rsBuff),
1, vb);
diff --git a/src/sg_unmap.c b/src/sg_unmap.c
index 2deb71ad..c24c676a 100644
--- a/src/sg_unmap.c
+++ b/src/sg_unmap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2018 Douglas Gilbert.
+ * Copyright (c) 2009-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.
@@ -29,16 +29,6 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-#if defined(MSC_VER) || defined(__MINGW32__)
-#define HAVE_MS_SLEEP
-#endif
-
-#ifdef HAVE_MS_SLEEP
-#include <windows.h>
-#define sleep_for(seconds) Sleep( (seconds) * 1000)
-#else
-#define sleep_for(seconds) sleep(seconds)
-#endif
/* A utility program originally written for the Linux OS SCSI subsystem.
*
@@ -46,7 +36,7 @@
* logical blocks. Note that DATA MAY BE LOST.
*/
-static const char * version_str = "1.17 20180628";
+static const char * version_str = "1.18 20220608";
#define DEF_TIMEOUT_SECS 60
@@ -676,25 +666,14 @@ main(int argc, char * argv[])
printf("%s is: %.8s %.16s %.4s\n", device_name,
inq_resp.vendor, inq_resp.product, inq_resp.revision);
- sleep_for(3);
+ sg_sleep_secs(3);
if (to_end_of_device)
- snprintf(b, sizeof(b), "LBA 0x%" PRIx64 " to end of %s "
- "(0x%" PRIx64 ")", all_start, device_name, all_last);
+ snprintf(b, sizeof(b), "%s from LBA 0x%" PRIx64 " to end "
+ "(0x%" PRIx64 ")", device_name, all_start, all_last);
else
- snprintf(b, sizeof(b), "LBA 0x%" PRIx64 " to 0x%" PRIx64
- " on %s", all_start, all_last, device_name);
- printf("\nAn UNMAP (a.k.a. trim) will commence in 15 seconds\n");
- printf(" ALL data from %s will be LOST\n", b);
- printf(" Press control-C to abort\n");
- sleep_for(5);
- printf("\nAn UNMAP will commence in 10 seconds\n");
- printf(" ALL data from %s will be LOST\n", b);
- printf(" Press control-C to abort\n");
- sleep_for(5);
- printf("\nAn UNMAP (a.k.a. trim) will commence in 5 seconds\n");
- printf(" ALL data from %s will be LOST\n", b);
- printf(" Press control-C to abort\n");
- sleep_for(7);
+ snprintf(b, sizeof(b), "%s from LBA 0x%" PRIx64 " to 0x%"
+ PRIx64, device_name, all_start, all_last);
+ sg_warn_and_wait("UNMAP (a.k.a. trim)", b, false);
}
if (dry_run) {
pr2serr("Doing dry-run, would have unmapped from LBA 0x%" PRIx64
@@ -757,19 +736,19 @@ retry:
if (! do_force) {
printf("%s is: %.8s %.16s %.4s\n", device_name,
inq_resp.vendor, inq_resp.product, inq_resp.revision);
- sleep_for(3);
+ sg_sleep_secs(3);
printf("\nAn UNMAP (a.k.a. trim) will commence in 15 seconds\n");
printf(" Some data will be LOST\n");
printf(" Press control-C to abort\n");
- sleep_for(5);
+ sg_sleep_secs(5);
printf("\nAn UNMAP will commence in 10 seconds\n");
printf(" Some data will be LOST\n");
printf(" Press control-C to abort\n");
- sleep_for(5);
+ sg_sleep_secs(5);
printf("\nAn UNMAP (a.k.a. trim) will commence in 5 seconds\n");
printf(" Some data will be LOST\n");
printf(" Press control-C to abort\n");
- sleep_for(7);
+ sg_sleep_secs(7);
}
res = sg_ll_unmap_v2(sg_fd, anchor, grpnum, timeout, param_arr,
param_len, true, vb);
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 9350dbc6..20f74b5c 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -40,7 +40,7 @@
*/
-static const char * version_str = "1.70 20220218"; /* spc6r06 + sbc5r01 */
+static const char * version_str = "1.71 20220608"; /* spc6r06 + sbc5r01 */
/* standard VPD pages, in ascending page number order */
#define VPD_SUPPORTED_VPDS 0x0
diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c
index d79ccc7d..a1a1a501 100644
--- a/src/sg_vpd_vendor.c
+++ b/src/sg_vpd_vendor.c
@@ -1558,6 +1558,6 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, int off)
return 0;
}
} else
- pr2serr("Vendor VPD page=0x%x failed to fetch", op->vpd_pn);
+ pr2serr("Vendor VPD page=0x%x failed to fetch\n", op->vpd_pn);
return res;
}
diff --git a/src/sg_zone.c b/src/sg_zone.c
index ff4dc366..e4540143 100644
--- a/src/sg_zone.c
+++ b/src/sg_zone.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2021 Douglas Gilbert.
+ * Copyright (c) 2014-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.
@@ -32,12 +32,15 @@
/* A utility program originally written for the Linux OS SCSI subsystem.
*
- *
- * This program issues a SCSI CLOSE ZONE, FINISH ZONE or OPEN ZONE command
- * to the given SCSI device. Based on zbc-r04c.pdf .
+ * This program issues one of the following SCSI commands:
+ * - CLOSE ZONE
+ * - FINISH ZONE
+ * - OPEN ZONE
+ * - REMOVE ELEMENT AND MODIFY ZONES
+ * - SEQUENTIALIZE ZONE
*/
-static const char * version_str = "1.17 20211114";
+static const char * version_str = "1.18 20220609";
#define SG_ZONING_OUT_CMDLEN 16
#define CLOSE_ZONE_SA 0x1
@@ -58,6 +61,7 @@ static struct option long_options[] = {
{"finish", no_argument, 0, 'f'},
{"help", no_argument, 0, 'h'},
{"open", no_argument, 0, 'o'},
+ {"quick", no_argument, 0, 'q'},
{"remove", no_argument, 0, 'r'},
{"reset-all", no_argument, 0, 'R'}, /* same as --all */
{"reset_all", no_argument, 0, 'R'},
@@ -68,14 +72,14 @@ static struct option long_options[] = {
{0, 0, 0, 0},
};
-/* Indexed by service action */
+/* Indexed by service action of opcode 0x94 (Zone out) unless noted */
static const char * sa_name_arr[] = {
"no SA=0", /* 0x0 */
"Close zone",
"Finish zone",
"Open zone",
"-", "-", "-", "-",
- "Zone activate", /* 0x8 */
+ "-",
"-", "-", "-", "-",
"-",
"-",
@@ -84,7 +88,7 @@ static const char * sa_name_arr[] = {
"-", "-", "-", "-",
"-", "-", "-", "-",
"-",
- "Remove element and modify zones", /* 0x1a */
+ "Remove element and modify zones", /* service action in(16), 0x1a */
};
@@ -94,10 +98,9 @@ usage()
pr2serr("Usage: "
"sg_zone [--all] [--close] [--count=ZC] [--element=EID] "
"[--finish]\n"
- " [--help] [--open] [--remove] "
- "[--sequentialize] "
- "[--verbose]\n"
- " [--version] [--zone=ID] DEVICE\n");
+ " [--help] [--open] [--quick] [--remove] "
+ "[--sequentialize]\n"
+ " [--verbose] [--version] [--zone=ID] DEVICE\n");
pr2serr(" where:\n"
" --all|-a sets the ALL flag in the cdb\n"
" --close|-c issue CLOSE ZONE command\n"
@@ -109,6 +112,8 @@ usage()
" --finish|-f issue FINISH ZONE command\n"
" --help|-h print out usage message\n"
" --open|-o issue OPEN ZONE command\n"
+ " --quick|-q bypass 15 second warn and wait "
+ "(for --remove)\n"
" --remove|-r issue REMOVE ELEMENT AND MODIFY ZONES "
"command\n"
" --sequentialize|-S issue SEQUENTIALIZE ZONE command\n"
@@ -116,11 +121,10 @@ usage()
" --version|-V print version string and exit\n"
" --zone=ID|-z ID ID is the starting LBA of the zone "
"(def: 0)\n\n"
- "Performs a SCSI OPEN ZONE, CLOSE ZONE, FINISH ZONE or "
- "SEQUENTIALIZE\nZONE command. ID is decimal by default, for hex "
- "use a leading '0x'\nor a trailing 'h'. Either --close, "
- "--finish, --open, --remove or\n--sequentialize option needs to "
- "be given.\n");
+ "Performs a SCSI OPEN ZONE, CLOSE ZONE, FINISH ZONE, "
+ "REMOVE ELEMENT AND\nMODIFY ZONES or SEQUENTIALIZE ZONE "
+ "command. Either --close, --finish,\n--open, --remove or "
+ "--sequentialize option needs to be given.\n");
}
/* Invokes the zone out command indicated by 'sa' (ZBC). Return of 0
@@ -139,7 +143,7 @@ sg_ll_zone_out(int sg_fd, int sa, uint64_t zid, uint16_t zc, bool all,
zo_cdb[1] = 0x1f & sa;
if (REM_ELEM_MOD_ZONES_SA == sa) { /* zid carries element identifier */
zo_cdb[0] = SG_SERVICE_ACTION_IN_16; /* N.B. changing opcode */
- sg_put_unaligned_be32((uint32_t)zid, zo_cdb + 10);
+ sg_put_unaligned_be32((uint32_t)zid, zo_cdb + 10); /* element id */
} else {
sg_put_unaligned_be64(zid, zo_cdb + 2);
sg_put_unaligned_be16(zc, zo_cdb + 12);
@@ -194,7 +198,9 @@ main(int argc, char * argv[])
bool close = false;
bool finish = false;
bool open = false;
+ bool quick = false;
bool reamz = false;
+ bool element_id_given = false;
bool sequentialize = false;
bool verbose_given = false;
bool version_given = false;
@@ -212,7 +218,7 @@ main(int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "acC:e:fhorRSvVz:", long_options,
+ c = getopt_long(argc, argv, "acC:e:fhoqrRSvVz:", long_options,
&option_index);
if (c == -1)
break;
@@ -243,7 +249,8 @@ main(int argc, char * argv[])
}
if (0 == ll)
pr2serr("Warning: 0 is an invalid element identifier\n");
- zid = (uint64_t)ll;
+ zid = (uint64_t)ll; /* putting element_id in zid */
+ element_id_given = true;
break;
case 'f':
finish = true;
@@ -257,6 +264,9 @@ main(int argc, char * argv[])
open = true;
sa = OPEN_ZONE_SA;
break;
+ case 'q':
+ quick = true;
+ break;
case 'r':
reamz = true;
sa = REM_ELEM_MOD_ZONES_SA;
@@ -323,8 +333,15 @@ main(int argc, char * argv[])
if (1 != ((int)close + (int)finish + (int)open + (int)sequentialize +
(int)reamz)) {
- pr2serr("one of these options: --close, --finish, --open "
- "--sequentialize and\n--remove must be given\n");
+ pr2serr("One, and only one, of these options needs to be given:\n"
+ " --close, --finish, --open, --remove or --sequentialize "
+ "\n\n");
+ usage();
+ return SG_LIB_CONTRADICT;
+ }
+ if (element_id_given && (! reamz)) {
+ pr2serr("The --element=EID option should only be used with the "
+ "--remove option\n\n");
usage();
return SG_LIB_CONTRADICT;
}
@@ -345,6 +362,9 @@ main(int argc, char * argv[])
ret = sg_convert_errno(err);
goto fini;
}
+ if (reamz && (! quick))
+ sg_warn_and_wait(sa_name_arr[REM_ELEM_MOD_ZONES_SA], device_name,
+ false);
res = sg_ll_zone_out(sg_fd, sa, zid, zc, all, true, verbose);
ret = res;
diff --git a/testing/sg_mrq_dd.cpp b/testing/sg_mrq_dd.cpp
index 9f17146c..0706f1af 100644
--- a/testing/sg_mrq_dd.cpp
+++ b/testing/sg_mrq_dd.cpp
@@ -30,7 +30,7 @@
*
*/
-static const char * version_str = "1.41 20220413";
+static const char * version_str = "1.42 20220615";
#define _XOPEN_SOURCE 600
#ifndef _GNU_SOURCE
@@ -1912,7 +1912,7 @@ normal_in_rd(Rq_elem * rep, int64_t lba, int blocks, int d_boff)
if (clp->in_flags.zero && clp->in_flags.ff && (rep->bs >= 4)) {
uint32_t pos = (uint32_t)lba;
- uint off;
+ uint32_t off;
for (k = 0, off = 0; k < blocks; ++k, off += rep->bs, ++pos) {
for (j = 0; j < (rep->bs - 3); j += 4)
diff --git a/testing/sg_tst_json_builder.c b/testing/sg_tst_json_builder.c
index 039c10fe..d48e8cfe 100644
--- a/testing/sg_tst_json_builder.c
+++ b/testing/sg_tst_json_builder.c
@@ -68,7 +68,8 @@ main(int argc, char * argv[])
printf("jv2p->type=%d\n", jv2p->type);
else
printf("jv2p is NULL\n");
- ja2p = json_array_push(ja1p, json_string_new("hello world 99"));
+ ja2p = json_array_push(ja1p, json_string_new(
+ "test double quote, etc: \" world \\ 99\t\ttwo tabs"));
if (ja2p)
printf("ja2p->type=%d\n", ja2p->type);
else
diff --git a/testing/sgh_dd.cpp b/testing/sgh_dd.cpp
index 90577f88..0985449a 100644
--- a/testing/sgh_dd.cpp
+++ b/testing/sgh_dd.cpp
@@ -36,7 +36,7 @@
* renamed [20181221]
*/
-static const char * version_str = "2.19 20220118";
+static const char * version_str = "2.20 20220616";
#define _XOPEN_SOURCE 600
#ifndef _GNU_SOURCE
@@ -1893,7 +1893,7 @@ normal_in_rd(Rq_elem * rep, int blocks)
if (clp->in_flags.zero && clp->in_flags.ff && (rep->bs >= 4)) {
uint32_t pos = (uint32_t)rep->iblk;
- uint off;
+ uint32_t off;
for (k = 0, off = 0; k < blocks; ++k, off += rep->bs, ++pos) {
for (j = 0; j < (rep->bs - 3); j += 4)