xref: /aosp_15_r20/external/sg3_utils/src/sg_decode_sense.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  * Copyright (c) 2010-2022 Douglas Gilbert.
3*44704f69SBart Van Assche  * All rights reserved.
4*44704f69SBart Van Assche  * Use of this source code is governed by a BSD-style
5*44704f69SBart Van Assche  * license that can be found in the BSD_LICENSE file.
6*44704f69SBart Van Assche  *
7*44704f69SBart Van Assche  * SPDX-License-Identifier: BSD-2-Clause
8*44704f69SBart Van Assche  */
9*44704f69SBart Van Assche 
10*44704f69SBart Van Assche #include <unistd.h>
11*44704f69SBart Van Assche #include <fcntl.h>
12*44704f69SBart Van Assche #include <stdio.h>
13*44704f69SBart Van Assche #include <stdlib.h>
14*44704f69SBart Van Assche #include <stdbool.h>
15*44704f69SBart Van Assche #include <string.h>
16*44704f69SBart Van Assche #include <errno.h>
17*44704f69SBart Van Assche #include <limits.h>
18*44704f69SBart Van Assche #include <ctype.h>
19*44704f69SBart Van Assche #include <sys/types.h>
20*44704f69SBart Van Assche #include <sys/stat.h>
21*44704f69SBart Van Assche #include <getopt.h>
22*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
23*44704f69SBart Van Assche #include <inttypes.h>
24*44704f69SBart Van Assche 
25*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
26*44704f69SBart Van Assche #include "config.h"
27*44704f69SBart Van Assche #endif
28*44704f69SBart Van Assche #include "sg_lib.h"
29*44704f69SBart Van Assche #include "sg_pr2serr.h"
30*44704f69SBart Van Assche #include "sg_unaligned.h"
31*44704f69SBart Van Assche 
32*44704f69SBart Van Assche 
33*44704f69SBart Van Assche static const char * version_str = "1.32 20220730";
34*44704f69SBart Van Assche 
35*44704f69SBart Van Assche #define MY_NAME "sg_decode_sense"
36*44704f69SBart Van Assche 
37*44704f69SBart Van Assche #define MAX_SENSE_LEN 8192 /* max descriptor format actually: 255+8 */
38*44704f69SBart Van Assche 
39*44704f69SBart Van Assche static struct option long_options[] = {
40*44704f69SBart Van Assche     {"binary", required_argument, 0, 'b'},
41*44704f69SBart Van Assche     {"cdb", no_argument, 0, 'c'},
42*44704f69SBart Van Assche     {"err", required_argument, 0, 'e'},
43*44704f69SBart Van Assche     {"exit-status", required_argument, 0, 'e'},
44*44704f69SBart Van Assche     {"exit_status", required_argument, 0, 'e'},
45*44704f69SBart Van Assche     {"file", required_argument, 0, 'f'},
46*44704f69SBart Van Assche     {"help", no_argument, 0, 'h'},
47*44704f69SBart Van Assche     {"hex", no_argument, 0, 'H'},
48*44704f69SBart Van Assche     {"in", required_argument, 0, 'i'},          /* don't advertise */
49*44704f69SBart Van Assche     {"inhex", required_argument, 0, 'i'},       /* same as --file */
50*44704f69SBart Van Assche     {"ignore-first", no_argument, 0, 'I'},
51*44704f69SBart Van Assche     {"ignore_first", no_argument, 0, 'I'},
52*44704f69SBart Van Assche     {"json", optional_argument, 0, 'j'},
53*44704f69SBart Van Assche     {"nodecode", no_argument, 0, 'N'},
54*44704f69SBart Van Assche     {"nospace", no_argument, 0, 'n'},
55*44704f69SBart Van Assche     {"status", required_argument, 0, 's'},
56*44704f69SBart Van Assche     {"verbose", no_argument, 0, 'v'},
57*44704f69SBart Van Assche     {"version", no_argument, 0, 'V'},
58*44704f69SBart Van Assche     {"write", required_argument, 0, 'w'},
59*44704f69SBart Van Assche     {0, 0, 0, 0},
60*44704f69SBart Van Assche };
61*44704f69SBart Van Assche 
62*44704f69SBart Van Assche struct opts_t {
63*44704f69SBart Van Assche     bool do_binary;
64*44704f69SBart Van Assche     bool do_cdb;
65*44704f69SBart Van Assche     bool do_help;
66*44704f69SBart Van Assche     bool no_decode;
67*44704f69SBart Van Assche     bool no_space;
68*44704f69SBart Van Assche     bool do_status;
69*44704f69SBart Van Assche     bool verbose_given;
70*44704f69SBart Van Assche     bool version_given;
71*44704f69SBart Van Assche     bool err_given;
72*44704f69SBart Van Assche     bool file_given;
73*44704f69SBart Van Assche     bool ignore_first;
74*44704f69SBart Van Assche     const char * fname;
75*44704f69SBart Van Assche     int es_val;
76*44704f69SBart Van Assche     int hex_count;
77*44704f69SBart Van Assche     int sense_len;
78*44704f69SBart Van Assche     int sstatus;
79*44704f69SBart Van Assche     int verbose;
80*44704f69SBart Van Assche     const char * wfname;
81*44704f69SBart Van Assche     const char * no_space_str;
82*44704f69SBart Van Assche     sgj_state json_st;
83*44704f69SBart Van Assche     uint8_t sense[MAX_SENSE_LEN + 4];
84*44704f69SBart Van Assche };
85*44704f69SBart Van Assche 
86*44704f69SBart Van Assche static char concat_buff[1024];
87*44704f69SBart Van Assche 
88*44704f69SBart Van Assche 
89*44704f69SBart Van Assche static void
usage()90*44704f69SBart Van Assche usage()
91*44704f69SBart Van Assche {
92*44704f69SBart Van Assche   pr2serr("Usage: sg_decode_sense [--binary=BFN] [--cdb] [--err=ES] "
93*44704f69SBart Van Assche           "[--file=HFN]\n"
94*44704f69SBart Van Assche           "                       [--help] [--hex] [--inhex=HFN] "
95*44704f69SBart Van Assche           "[--ignore-first]\n"
96*44704f69SBart Van Assche           "                       [--json[=JO]] [--nodecode] [--nospace] "
97*44704f69SBart Van Assche           "[--status=SS]\n"
98*44704f69SBart Van Assche           "                       [--verbose] [--version] [--write=WFN] "
99*44704f69SBart Van Assche           "H1 H2 H3 ...\n"
100*44704f69SBart Van Assche           "  where:\n"
101*44704f69SBart Van Assche           "    --binary=BFN|-b BFN    BFN is a file name to read sense "
102*44704f69SBart Van Assche           "data in\n"
103*44704f69SBart Van Assche           "                          binary from. If BFN is '-' then read "
104*44704f69SBart Van Assche           "from stdin\n"
105*44704f69SBart Van Assche           "    --cdb|-c              decode given hex as cdb rather than "
106*44704f69SBart Van Assche           "sense data\n"
107*44704f69SBart Van Assche           "    --err=ES|-e ES        ES is Exit Status from utility in this "
108*44704f69SBart Van Assche           "package\n"
109*44704f69SBart Van Assche           "    --file=HFN|-f HFN     HFN is a file name from which to read "
110*44704f69SBart Van Assche           "sense data\n"
111*44704f69SBart Van Assche           "                          in ASCII hexadecimal. Interpret '-' "
112*44704f69SBart Van Assche           "as stdin\n"
113*44704f69SBart Van Assche           "    --help|-h             print out usage message\n"
114*44704f69SBart Van Assche           "    --hex|-H              used together with --write=WFN, to "
115*44704f69SBart Van Assche           "write out\n"
116*44704f69SBart Van Assche           "                          C language style ASCII hex (instead "
117*44704f69SBart Van Assche           "of binary).\n"
118*44704f69SBart Van Assche           "                          Otherwise don't decode, output incoming "
119*44704f69SBart Van Assche           "data in\n"
120*44704f69SBart Van Assche           "                          hex (used '-HH' or '-HHH' for different "
121*44704f69SBart Van Assche           "formats)\n"
122*44704f69SBart Van Assche           "    --inhex=HFN|-i HFN    same as action as --file=HFN\n"
123*44704f69SBart Van Assche           "    --ignore-first|-I     when reading hex (e.g. with --file=HFN) "
124*44704f69SBart Van Assche           "skip\n"
125*44704f69SBart Van Assche           "                          the first hexadecimal value on each "
126*44704f69SBart Van Assche           "line\n"
127*44704f69SBart Van Assche           "    --json[=JO]|-j[JO]    output in JSON instead of human "
128*44704f69SBart Van Assche           "readable text.\n"
129*44704f69SBart Van Assche           "                          Use --json=? for JSON help\n"
130*44704f69SBart Van Assche           "    --nodecode|-N         do not decode, may be neither sense "
131*44704f69SBart Van Assche           "nor cdb\n"
132*44704f69SBart Van Assche           "    --nospace|-n          no spaces or other separators between "
133*44704f69SBart Van Assche           "pairs of\n"
134*44704f69SBart Van Assche           "                          hex digits (e.g. '3132330A')\n"
135*44704f69SBart Van Assche           "    --status=SS |-s SS    SCSI status value in hex\n"
136*44704f69SBart Van Assche           "    --verbose|-v          increase verbosity\n"
137*44704f69SBart Van Assche           "    --version|-V          print version string then exit\n"
138*44704f69SBart Van Assche           "    --write=WFN |-w WFN    write sense data in binary to WFN, "
139*44704f69SBart Van Assche           "create if\n"
140*44704f69SBart Van Assche           "                           required else truncate prior to "
141*44704f69SBart Van Assche           "writing\n\n"
142*44704f69SBart Van Assche           "Decodes SCSI sense data given on the command line as a sequence "
143*44704f69SBart Van Assche           "of\nhexadecimal bytes (H1 H2 H3 ...) . Alternatively the sense "
144*44704f69SBart Van Assche           "data can\nbe in a binary file or in a file containing ASCII "
145*44704f69SBart Van Assche           "hexadecimal. If\n'--cdb' is given then interpret hex as SCSI CDB "
146*44704f69SBart Van Assche           "rather than sense data.\n"
147*44704f69SBart Van Assche           );
148*44704f69SBart Van Assche }
149*44704f69SBart Van Assche 
150*44704f69SBart Van Assche static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[])151*44704f69SBart Van Assche parse_cmd_line(struct opts_t *op, int argc, char *argv[])
152*44704f69SBart Van Assche {
153*44704f69SBart Van Assche     int c, n;
154*44704f69SBart Van Assche     unsigned int ui;
155*44704f69SBart Van Assche     long val;
156*44704f69SBart Van Assche     char * avp;
157*44704f69SBart Van Assche     char *endptr;
158*44704f69SBart Van Assche 
159*44704f69SBart Van Assche     while (1) {
160*44704f69SBart Van Assche         c = getopt_long(argc, argv, "b:ce:f:hHi:Ij::nNs:vVw:", long_options,
161*44704f69SBart Van Assche                         NULL);
162*44704f69SBart Van Assche         if (c == -1)
163*44704f69SBart Van Assche             break;
164*44704f69SBart Van Assche 
165*44704f69SBart Van Assche         switch (c) {
166*44704f69SBart Van Assche         case 'b':
167*44704f69SBart Van Assche             if (op->fname) {
168*44704f69SBart Van Assche                 pr2serr("expect only one '--binary=BFN', '--file=HFN' or "
169*44704f69SBart Van Assche                         "'--inhex=HFN' option\n");
170*44704f69SBart Van Assche                 return SG_LIB_CONTRADICT;
171*44704f69SBart Van Assche             }
172*44704f69SBart Van Assche             op->do_binary = true;
173*44704f69SBart Van Assche             op->fname = optarg;
174*44704f69SBart Van Assche             break;
175*44704f69SBart Van Assche         case 'c':
176*44704f69SBart Van Assche             op->do_cdb = true;
177*44704f69SBart Van Assche             break;
178*44704f69SBart Van Assche         case 'e':
179*44704f69SBart Van Assche             n = sg_get_num(optarg);
180*44704f69SBart Van Assche             if ((n < 0) || (n > 255)) {
181*44704f69SBart Van Assche                 pr2serr("--err= expected number from 0 to 255 inclusive\n");
182*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
183*44704f69SBart Van Assche             }
184*44704f69SBart Van Assche             op->err_given = true;
185*44704f69SBart Van Assche             op->es_val = n;
186*44704f69SBart Van Assche             break;
187*44704f69SBart Van Assche         case 'f':
188*44704f69SBart Van Assche             if (op->fname) {
189*44704f69SBart Van Assche                 pr2serr("expect only one '--binary=BFN', '--file=HFN' or "
190*44704f69SBart Van Assche                         "'--inhex=HFN' option\n");
191*44704f69SBart Van Assche                 return SG_LIB_CONTRADICT;
192*44704f69SBart Van Assche             }
193*44704f69SBart Van Assche             op->file_given = true;
194*44704f69SBart Van Assche             op->fname = optarg;
195*44704f69SBart Van Assche             break;
196*44704f69SBart Van Assche         case 'h':
197*44704f69SBart Van Assche         case '?':
198*44704f69SBart Van Assche             op->do_help = true;
199*44704f69SBart Van Assche             return 0;
200*44704f69SBart Van Assche         case 'H':
201*44704f69SBart Van Assche             op->hex_count++;
202*44704f69SBart Van Assche             break;
203*44704f69SBart Van Assche         case 'i':
204*44704f69SBart Van Assche             if (op->fname) {
205*44704f69SBart Van Assche                 pr2serr("expect only one '--binary=BFN', '--file=HFN' or "
206*44704f69SBart Van Assche                         "'--inhex=HFN' option\n");
207*44704f69SBart Van Assche                 return SG_LIB_CONTRADICT;
208*44704f69SBart Van Assche             }
209*44704f69SBart Van Assche             op->file_given = true;
210*44704f69SBart Van Assche             op->fname = optarg;
211*44704f69SBart Van Assche             break;
212*44704f69SBart Van Assche         case 'I':
213*44704f69SBart Van Assche             op->ignore_first = true;
214*44704f69SBart Van Assche             break;
215*44704f69SBart Van Assche        case 'j':
216*44704f69SBart Van Assche             if (! sgj_init_state(&op->json_st, optarg)) {
217*44704f69SBart Van Assche                 int bad_char = op->json_st.first_bad_char;
218*44704f69SBart Van Assche                 char e[1500];
219*44704f69SBart Van Assche 
220*44704f69SBart Van Assche                 if (bad_char) {
221*44704f69SBart Van Assche                     pr2serr("bad argument to --json= option, unrecognized "
222*44704f69SBart Van Assche                             "character '%c'\n\n", bad_char);
223*44704f69SBart Van Assche                 }
224*44704f69SBart Van Assche                 sg_json_usage(0, e, sizeof(e));
225*44704f69SBart Van Assche                 pr2serr("%s", e);
226*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
227*44704f69SBart Van Assche             }
228*44704f69SBart Van Assche             break;
229*44704f69SBart Van Assche         case 'n':
230*44704f69SBart Van Assche             op->no_space = true;
231*44704f69SBart Van Assche             break;
232*44704f69SBart Van Assche         case 'N':
233*44704f69SBart Van Assche             op->no_decode = true;
234*44704f69SBart Van Assche             break;
235*44704f69SBart Van Assche         case 's':
236*44704f69SBart Van Assche             if (1 != sscanf(optarg, "%x", &ui)) {
237*44704f69SBart Van Assche                 pr2serr("'--status=SS' expects a byte value\n");
238*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
239*44704f69SBart Van Assche             }
240*44704f69SBart Van Assche             if (ui > 0xff) {
241*44704f69SBart Van Assche                 pr2serr("'--status=SS' byte value exceeds FF\n");
242*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
243*44704f69SBart Van Assche             }
244*44704f69SBart Van Assche             op->do_status = true;
245*44704f69SBart Van Assche             op->sstatus = ui;
246*44704f69SBart Van Assche             break;
247*44704f69SBart Van Assche         case 'v':
248*44704f69SBart Van Assche             op->verbose_given = true;
249*44704f69SBart Van Assche             ++op->verbose;
250*44704f69SBart Van Assche             break;
251*44704f69SBart Van Assche         case 'V':
252*44704f69SBart Van Assche             op->version_given = true;
253*44704f69SBart Van Assche             break;
254*44704f69SBart Van Assche         case 'w':
255*44704f69SBart Van Assche             op->wfname = optarg;
256*44704f69SBart Van Assche             break;
257*44704f69SBart Van Assche         default:
258*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
259*44704f69SBart Van Assche         }
260*44704f69SBart Van Assche     }
261*44704f69SBart Van Assche     if (op->err_given)
262*44704f69SBart Van Assche         goto the_end;
263*44704f69SBart Van Assche 
264*44704f69SBart Van Assche     while (optind < argc) {
265*44704f69SBart Van Assche         avp = argv[optind++];
266*44704f69SBart Van Assche         if (op->no_space) {
267*44704f69SBart Van Assche             if (op->no_space_str) {
268*44704f69SBart Van Assche                 if ('\0' == concat_buff[0]) {
269*44704f69SBart Van Assche                     if (strlen(op->no_space_str) > sizeof(concat_buff)) {
270*44704f69SBart Van Assche                         pr2serr("'--nospace' concat_buff overflow\n");
271*44704f69SBart Van Assche                         return SG_LIB_SYNTAX_ERROR;
272*44704f69SBart Van Assche                     }
273*44704f69SBart Van Assche                     strcpy(concat_buff, op->no_space_str);
274*44704f69SBart Van Assche                 }
275*44704f69SBart Van Assche                 if ((strlen(concat_buff) + strlen(avp)) >=
276*44704f69SBart Van Assche                     sizeof(concat_buff)) {
277*44704f69SBart Van Assche                     pr2serr("'--nospace' concat_buff overflow\n");
278*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
279*44704f69SBart Van Assche                 }
280*44704f69SBart Van Assche                 if (op->version_given)
281*44704f69SBart Van Assche                     pr2serr("'--nospace' and found whitespace so "
282*44704f69SBart Van Assche                             "concatenate\n");
283*44704f69SBart Van Assche                 strcat(concat_buff, avp);
284*44704f69SBart Van Assche                 op->no_space_str = concat_buff;
285*44704f69SBart Van Assche             } else
286*44704f69SBart Van Assche                 op->no_space_str = avp;
287*44704f69SBart Van Assche             continue;
288*44704f69SBart Van Assche         }
289*44704f69SBart Van Assche         val = strtol(avp, &endptr, 16);
290*44704f69SBart Van Assche         if (*avp == '\0' || *endptr != '\0' || val < 0x00 || val > 0xff) {
291*44704f69SBart Van Assche             pr2serr("Invalid byte '%s'\n", avp);
292*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
293*44704f69SBart Van Assche         }
294*44704f69SBart Van Assche 
295*44704f69SBart Van Assche         if (op->sense_len > MAX_SENSE_LEN) {
296*44704f69SBart Van Assche             pr2serr("sense data too long (max. %d bytes)\n", MAX_SENSE_LEN);
297*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
298*44704f69SBart Van Assche         }
299*44704f69SBart Van Assche         op->sense[op->sense_len++] = (uint8_t)val;
300*44704f69SBart Van Assche     }
301*44704f69SBart Van Assche the_end:
302*44704f69SBart Van Assche     return 0;
303*44704f69SBart Van Assche }
304*44704f69SBart Van Assche 
305*44704f69SBart Van Assche /* Keep this format (e.g. 0xff,0x12,...) for backward compatibility */
306*44704f69SBart Van Assche static void
write2wfn(FILE * fp,struct opts_t * op)307*44704f69SBart Van Assche write2wfn(FILE * fp, struct opts_t * op)
308*44704f69SBart Van Assche {
309*44704f69SBart Van Assche     int k, n;
310*44704f69SBart Van Assche     size_t s;
311*44704f69SBart Van Assche     char b[128];
312*44704f69SBart Van Assche 
313*44704f69SBart Van Assche     for (k = 0, n = 0; k < op->sense_len; ++k) {
314*44704f69SBart Van Assche         n += sprintf(b + n, "0x%02x,", op->sense[k]);
315*44704f69SBart Van Assche         if (15 == (k % 16)) {
316*44704f69SBart Van Assche             b[n] = '\n';
317*44704f69SBart Van Assche             s = fwrite(b, 1, n + 1, fp);
318*44704f69SBart Van Assche             if ((int)s != (n + 1))
319*44704f69SBart Van Assche                 pr2serr("only able to write %d of %d bytes to %s\n",
320*44704f69SBart Van Assche                         (int)s, n + 1, op->wfname);
321*44704f69SBart Van Assche             n = 0;
322*44704f69SBart Van Assche         }
323*44704f69SBart Van Assche     }
324*44704f69SBart Van Assche     if (n > 0) {
325*44704f69SBart Van Assche         b[n] = '\n';
326*44704f69SBart Van Assche         s = fwrite(b, 1, n + 1, fp);
327*44704f69SBart Van Assche         if ((int)s != (n + 1))
328*44704f69SBart Van Assche             pr2serr("only able to write %d of %d bytes to %s\n", (int)s,
329*44704f69SBart Van Assche                     n + 1, op->wfname);
330*44704f69SBart Van Assche     }
331*44704f69SBart Van Assche }
332*44704f69SBart Van Assche 
333*44704f69SBart Van Assche 
334*44704f69SBart Van Assche int
main(int argc,char * argv[])335*44704f69SBart Van Assche main(int argc, char *argv[])
336*44704f69SBart Van Assche {
337*44704f69SBart Van Assche     bool as_json;
338*44704f69SBart Van Assche     int k, err, blen;
339*44704f69SBart Van Assche     int ret = 0;
340*44704f69SBart Van Assche     unsigned int ui;
341*44704f69SBart Van Assche     size_t s;
342*44704f69SBart Van Assche     struct opts_t * op;
343*44704f69SBart Van Assche     FILE * fp = NULL;
344*44704f69SBart Van Assche     const char * cp;
345*44704f69SBart Van Assche     sgj_state * jsp;
346*44704f69SBart Van Assche     sgj_opaque_p jop = NULL;
347*44704f69SBart Van Assche     uint8_t * free_op_buff = NULL;
348*44704f69SBart Van Assche     char b[2048];
349*44704f69SBart Van Assche 
350*44704f69SBart Van Assche     op = (struct opts_t *)sg_memalign(sizeof(*op), 0 /* page align */,
351*44704f69SBart Van Assche 				      &free_op_buff, false);
352*44704f69SBart Van Assche     if (NULL == op) {
353*44704f69SBart Van Assche         pr2serr("Unable to allocate heap for options structure\n");
354*44704f69SBart Van Assche         ret = sg_convert_errno(ENOMEM);
355*44704f69SBart Van Assche         goto clean_op;
356*44704f69SBart Van Assche     }
357*44704f69SBart Van Assche     blen = sizeof(b);
358*44704f69SBart Van Assche     memset(b, 0, blen);
359*44704f69SBart Van Assche     ret = parse_cmd_line(op, argc, argv);
360*44704f69SBart Van Assche 
361*44704f69SBart Van Assche #ifdef DEBUG
362*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
363*44704f69SBart Van Assche     if (op->verbose_given && op->version_given) {
364*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and continue\n");
365*44704f69SBart Van Assche         op->verbose_given = false;
366*44704f69SBart Van Assche         op->version_given = false;
367*44704f69SBart Van Assche         op->verbose = 0;
368*44704f69SBart Van Assche     } else if (! op->verbose_given) {
369*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
370*44704f69SBart Van Assche         op->verbose = 2;
371*44704f69SBart Van Assche     } else
372*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", op->verbose);
373*44704f69SBart Van Assche #else
374*44704f69SBart Van Assche     if (op->verbose_given && op->version_given)
375*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
376*44704f69SBart Van Assche #endif
377*44704f69SBart Van Assche     if (op->version_given) {
378*44704f69SBart Van Assche         pr2serr("version: %s\n", version_str);
379*44704f69SBart Van Assche         goto clean_op;
380*44704f69SBart Van Assche     }
381*44704f69SBart Van Assche     if (ret != 0) {
382*44704f69SBart Van Assche         usage();
383*44704f69SBart Van Assche         goto clean_op;
384*44704f69SBart Van Assche     } else if (op->do_help) {
385*44704f69SBart Van Assche         usage();
386*44704f69SBart Van Assche         goto clean_op;
387*44704f69SBart Van Assche     }
388*44704f69SBart Van Assche     as_json = op->json_st.pr_as_json;
389*44704f69SBart Van Assche     jsp = &op->json_st;
390*44704f69SBart Van Assche     if (as_json)
391*44704f69SBart Van Assche         jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp);
392*44704f69SBart Van Assche 
393*44704f69SBart Van Assche     if (op->err_given) {
394*44704f69SBart Van Assche         char d[128];
395*44704f69SBart Van Assche         const int dlen = sizeof(d);
396*44704f69SBart Van Assche 
397*44704f69SBart Van Assche         if (! sg_exit2str(op->es_val, op->verbose > 1, dlen, d))
398*44704f69SBart Van Assche             snprintf(d, dlen, "Unable to decode exit status %d", op->es_val);
399*44704f69SBart Van Assche         if (1 & op->verbose) /* odd values of verbose print to stderr */
400*44704f69SBart Van Assche             pr2serr("%s\n", d);
401*44704f69SBart Van Assche         else    /* even values of verbose (including not given) to stdout */
402*44704f69SBart Van Assche             printf("%s\n", d);
403*44704f69SBart Van Assche         goto fini;
404*44704f69SBart Van Assche     }
405*44704f69SBart Van Assche 
406*44704f69SBart Van Assche     if (op->do_status) {
407*44704f69SBart Van Assche         sg_get_scsi_status_str(op->sstatus, blen, b);
408*44704f69SBart Van Assche         printf("SCSI status: %s\n", b);
409*44704f69SBart Van Assche     }
410*44704f69SBart Van Assche 
411*44704f69SBart Van Assche     if ((0 == op->sense_len) && op->no_space_str) {
412*44704f69SBart Van Assche         if (op->verbose > 2)
413*44704f69SBart Van Assche             pr2serr("no_space str: %s\n", op->no_space_str);
414*44704f69SBart Van Assche         cp = op->no_space_str;
415*44704f69SBart Van Assche         for (k = 0; isxdigit((uint8_t)cp[k]) &&
416*44704f69SBart Van Assche                     isxdigit((uint8_t)cp[k + 1]); k += 2) {
417*44704f69SBart Van Assche             if (1 != sscanf(cp + k, "%2x", &ui)) {
418*44704f69SBart Van Assche                 pr2serr("bad no_space hex string: %s\n", cp);
419*44704f69SBart Van Assche                 ret = SG_LIB_SYNTAX_ERROR;
420*44704f69SBart Van Assche                 goto fini;
421*44704f69SBart Van Assche             }
422*44704f69SBart Van Assche             op->sense[op->sense_len++] = (uint8_t)ui;
423*44704f69SBart Van Assche         }
424*44704f69SBart Van Assche     }
425*44704f69SBart Van Assche 
426*44704f69SBart Van Assche     if ((0 == op->sense_len) && (! op->do_binary) && (! op->file_given)) {
427*44704f69SBart Van Assche         if (op->do_status) {
428*44704f69SBart Van Assche             ret = 0;
429*44704f69SBart Van Assche             goto fini;
430*44704f69SBart Van Assche         }
431*44704f69SBart Van Assche         pr2serr(">> Need sense/cdb/arbitrary data on the command line or "
432*44704f69SBart Van Assche                 "in a file\n\n");
433*44704f69SBart Van Assche         usage();
434*44704f69SBart Van Assche         ret = SG_LIB_SYNTAX_ERROR;
435*44704f69SBart Van Assche         goto fini;
436*44704f69SBart Van Assche     }
437*44704f69SBart Van Assche     if (op->sense_len && (op->do_binary || op->file_given)) {
438*44704f69SBart Van Assche         pr2serr(">> Need sense data on command line or in a file, not "
439*44704f69SBart Van Assche                 "both\n\n");
440*44704f69SBart Van Assche         ret = SG_LIB_CONTRADICT;
441*44704f69SBart Van Assche         goto fini;
442*44704f69SBart Van Assche     }
443*44704f69SBart Van Assche     if (op->do_binary && op->file_given) {
444*44704f69SBart Van Assche         pr2serr(">> Either a binary file or a ASCII hexadecimal, file not "
445*44704f69SBart Van Assche                 "both\n\n");
446*44704f69SBart Van Assche         ret = SG_LIB_CONTRADICT;
447*44704f69SBart Van Assche         goto fini;
448*44704f69SBart Van Assche     }
449*44704f69SBart Van Assche 
450*44704f69SBart Van Assche     if (op->do_binary) {
451*44704f69SBart Van Assche         fp = fopen(op->fname, "r");
452*44704f69SBart Van Assche         if (NULL == fp) {
453*44704f69SBart Van Assche             err = errno;
454*44704f69SBart Van Assche             pr2serr("unable to open file: %s: %s\n", op->fname,
455*44704f69SBart Van Assche                     safe_strerror(err));
456*44704f69SBart Van Assche             ret = sg_convert_errno(err);
457*44704f69SBart Van Assche             goto fini;
458*44704f69SBart Van Assche         }
459*44704f69SBart Van Assche         s = fread(op->sense, 1, MAX_SENSE_LEN, fp);
460*44704f69SBart Van Assche         fclose(fp);
461*44704f69SBart Van Assche         if (0 == s) {
462*44704f69SBart Van Assche             pr2serr("read nothing from file: %s\n", op->fname);
463*44704f69SBart Van Assche             ret = SG_LIB_SYNTAX_ERROR;
464*44704f69SBart Van Assche             goto fini;
465*44704f69SBart Van Assche         }
466*44704f69SBart Van Assche         op->sense_len = s;
467*44704f69SBart Van Assche     } else if (op->file_given) {
468*44704f69SBart Van Assche         ret = sg_f2hex_arr(op->fname, false, op->no_space, op->sense,
469*44704f69SBart Van Assche                            &op->sense_len,
470*44704f69SBart Van Assche                            (op->ignore_first ? -MAX_SENSE_LEN :
471*44704f69SBart Van Assche                                                MAX_SENSE_LEN));
472*44704f69SBart Van Assche         if (ret) {
473*44704f69SBart Van Assche             pr2serr("unable to decode ASCII hex from file: %s\n", op->fname);
474*44704f69SBart Van Assche             goto fini;
475*44704f69SBart Van Assche         }
476*44704f69SBart Van Assche     }
477*44704f69SBart Van Assche 
478*44704f69SBart Van Assche     if (op->sense_len > 0) {
479*44704f69SBart Van Assche         if (op->wfname || op->hex_count) {
480*44704f69SBart Van Assche             if (op->wfname) {
481*44704f69SBart Van Assche                 if (NULL == ((fp = fopen(op->wfname, "w")))) {
482*44704f69SBart Van Assche                     err =errno;
483*44704f69SBart Van Assche                     perror("open");
484*44704f69SBart Van Assche                     pr2serr("trying to write to %s\n", op->wfname);
485*44704f69SBart Van Assche                     ret = sg_convert_errno(err);
486*44704f69SBart Van Assche                     goto fini;
487*44704f69SBart Van Assche                 }
488*44704f69SBart Van Assche             } else
489*44704f69SBart Van Assche                 fp = stdout;
490*44704f69SBart Van Assche 
491*44704f69SBart Van Assche             if (op->wfname && (1 == op->hex_count))
492*44704f69SBart Van Assche                 write2wfn(fp, op);
493*44704f69SBart Van Assche             else if (op->hex_count && (2 != op->hex_count))
494*44704f69SBart Van Assche                 dStrHexFp((const char *)op->sense, op->sense_len,
495*44704f69SBart Van Assche                            ((1 == op->hex_count) ? 1 : -1), fp);
496*44704f69SBart Van Assche             else if (op->hex_count)
497*44704f69SBart Van Assche                 dStrHexFp((const char *)op->sense, op->sense_len, 0, fp);
498*44704f69SBart Van Assche             else {
499*44704f69SBart Van Assche                 s = fwrite(op->sense, 1, op->sense_len, fp);
500*44704f69SBart Van Assche                 if ((int)s != op->sense_len)
501*44704f69SBart Van Assche                     pr2serr("only able to write %d of %d bytes to %s\n",
502*44704f69SBart Van Assche                             (int)s, op->sense_len, op->wfname);
503*44704f69SBart Van Assche             }
504*44704f69SBart Van Assche             if (op->wfname)
505*44704f69SBart Van Assche                 fclose(fp);
506*44704f69SBart Van Assche         } else if (op->no_decode) {
507*44704f69SBart Van Assche             if (op->verbose > 1)
508*44704f69SBart Van Assche                 pr2serr("Not decoding as %s because --nodecode given\n",
509*44704f69SBart Van Assche                         (op->do_cdb ? "cdb" : "sense"));
510*44704f69SBart Van Assche         } else if (op->do_cdb) {
511*44704f69SBart Van Assche             int sa, opcode;
512*44704f69SBart Van Assche 
513*44704f69SBart Van Assche             opcode = op->sense[0];
514*44704f69SBart Van Assche             if ((0x75 == opcode) || (0x7e == opcode) || (op->sense_len > 16))
515*44704f69SBart Van Assche                 sa = sg_get_unaligned_be16(op->sense + 8);
516*44704f69SBart Van Assche             else if (op->sense_len > 1)
517*44704f69SBart Van Assche                 sa = op->sense[1] & 0x1f;
518*44704f69SBart Van Assche             else
519*44704f69SBart Van Assche                 sa = 0;
520*44704f69SBart Van Assche             sg_get_opcode_sa_name(opcode, sa, 0, blen, b);
521*44704f69SBart Van Assche             printf("%s\n", b);
522*44704f69SBart Van Assche         } else {
523*44704f69SBart Van Assche             if (as_json) {
524*44704f69SBart Van Assche                 sgj_js_sense(jsp, jop, op->sense, op->sense_len);
525*44704f69SBart Van Assche                 if (jsp->pr_out_hr) {
526*44704f69SBart Van Assche                     sg_get_sense_str(NULL, op->sense, op->sense_len,
527*44704f69SBart Van Assche                                      op->verbose, blen, b);
528*44704f69SBart Van Assche                      sgj_js_str_out(jsp, b, strlen(b));
529*44704f69SBart Van Assche                 }
530*44704f69SBart Van Assche             } else {
531*44704f69SBart Van Assche                 sg_get_sense_str(NULL, op->sense, op->sense_len,
532*44704f69SBart Van Assche                                  op->verbose, blen, b);
533*44704f69SBart Van Assche                 printf("%s\n", b);
534*44704f69SBart Van Assche             }
535*44704f69SBart Van Assche         }
536*44704f69SBart Van Assche     }
537*44704f69SBart Van Assche fini:
538*44704f69SBart Van Assche    if (as_json) {
539*44704f69SBart Van Assche         if (0 == op->hex_count)
540*44704f69SBart Van Assche             sgj_js2file(&op->json_st, NULL, ret, stdout);
541*44704f69SBart Van Assche         sgj_finish(jsp);
542*44704f69SBart Van Assche     }
543*44704f69SBart Van Assche clean_op:
544*44704f69SBart Van Assche     if (free_op_buff)
545*44704f69SBart Van Assche         free(free_op_buff);
546*44704f69SBart Van Assche     return ret;
547*44704f69SBart Van Assche }
548