• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1999-2018 Douglas Gilbert.
3  * All rights reserved.
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the BSD_LICENSE file.
6  */
7 
8 /* NOTICE:
9  *    On 5th October 2004 (v1.00) this file name was changed from sg_err.c
10  *    to sg_lib.c and the previous GPL was changed to a FreeBSD license.
11  *    The intention is to maintain this file and the related sg_lib.h file
12  *    as open source and encourage their unencumbered use.
13  *
14  * CONTRIBUTIONS:
15  *    This file started out as a copy of SCSI opcodes, sense keys and
16  *    additional sense codes (ASC/ASCQ) kept in the Linux SCSI subsystem
17  *    in the kernel source file: drivers/scsi/constant.c . That file
18  *    bore this notice: "Copyright (C) 1993, 1994, 1995 Eric Youngdale"
19  *    and a GPL notice.
20  *
21  *    Much of the data in this file is derived from SCSI draft standards
22  *    found at http://www.t10.org with the "SCSI Primary Commands-4" (SPC-4)
23  *    being the central point of reference.
24  *
25  *    Contributions:
26  *      sense key specific field decoding [Trent Piepho 20031116]
27  *
28  */
29 
30 #define _POSIX_C_SOURCE 200809L         /* for posix_memalign() */
31 #define __STDC_FORMAT_MACROS 1
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdbool.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <inttypes.h>
39 #include <errno.h>
40 
41 #ifdef HAVE_CONFIG_H
42 #include "config.h"
43 #endif
44 
45 #include "sg_lib.h"
46 #include "sg_lib_data.h"
47 #include "sg_unaligned.h"
48 #include "sg_pr2serr.h"
49 
50 /* sg_lib_version_str (and datestamp) defined in sg_lib_data.c file */
51 
52 #define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d  /* corresponding ASC is 0 */
53 
54 FILE * sg_warnings_strm = NULL;        /* would like to default to stderr */
55 
56 #if defined(__GNUC__) || defined(__clang__)
57 static int pr2ws(const char * fmt, ...)
58         __attribute__ ((format (printf, 1, 2)));
59 #else
60 static int pr2ws(const char * fmt, ...);
61 #endif
62 
63 
64 static int
pr2ws(const char * fmt,...)65 pr2ws(const char * fmt, ...)
66 {
67     va_list args;
68     int n;
69 
70     va_start(args, fmt);
71     n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
72     va_end(args);
73     return n;
74 }
75 
76 #if defined(__GNUC__) || defined(__clang__)
77 static int scnpr(char * cp, int cp_max_len, const char * fmt, ...)
78                  __attribute__ ((format (printf, 3, 4)));
79 #else
80 static int scnpr(char * cp, int cp_max_len, const char * fmt, ...);
81 #endif
82 
83 /* Want safe, 'n += snprintf(b + n, blen - n, ...)' style sequence of
84  * functions. Returns number of chars placed in cp excluding the
85  * trailing null char. So for cp_max_len > 0 the return value is always
86  * < cp_max_len; for cp_max_len <= 1 the return value is 0 and no chars are
87  * written to cp. Note this means that when cp_max_len = 1, this function
88  * assumes that cp[0] is the null character and does nothing (and returns
89  * 0). Linux kernel has a similar function called  scnprintf().  */
90 static int
scnpr(char * cp,int cp_max_len,const char * fmt,...)91 scnpr(char * cp, int cp_max_len, const char * fmt, ...)
92 {
93     va_list args;
94     int n;
95 
96     if (cp_max_len < 2)
97         return 0;
98     va_start(args, fmt);
99     n = vsnprintf(cp, cp_max_len, fmt, args);
100     va_end(args);
101     return (n < cp_max_len) ? n : (cp_max_len - 1);
102 }
103 
104 /* Simple ASCII printable (does not use locale), includes space and excludes
105  * DEL (0x7f). */
my_isprint(int ch)106 static inline int my_isprint(int ch)
107 {
108     return ((ch >= ' ') && (ch < 0x7f));
109 }
110 
111 /* Searches 'arr' for match on 'value' then 'peri_type'. If matches
112    'value' but not 'peri_type' then yields first 'value' match entry.
113    Last element of 'arr' has NULL 'name'. If no match returns NULL. */
114 static const struct sg_lib_value_name_t *
get_value_name(const struct sg_lib_value_name_t * arr,int value,int peri_type)115 get_value_name(const struct sg_lib_value_name_t * arr, int value,
116                int peri_type)
117 {
118     const struct sg_lib_value_name_t * vp = arr;
119     const struct sg_lib_value_name_t * holdp;
120 
121     if (peri_type < 0)
122         peri_type = 0;
123     for (; vp->name; ++vp) {
124         if (value == vp->value) {
125             if (peri_type == vp->peri_dev_type)
126                 return vp;
127             holdp = vp;
128             while ((vp + 1)->name && (value == (vp + 1)->value)) {
129                 ++vp;
130                 if (peri_type == vp->peri_dev_type)
131                     return vp;
132             }
133             return holdp;
134         }
135     }
136     return NULL;
137 }
138 
139 /* If this function is not called, sg_warnings_strm will be NULL and all users
140  * (mainly fprintf() ) need to check and substitute stderr as required */
141 void
sg_set_warnings_strm(FILE * warnings_strm)142 sg_set_warnings_strm(FILE * warnings_strm)
143 {
144     sg_warnings_strm = warnings_strm;
145 }
146 
147 #define CMD_NAME_LEN 128
148 
149 void
sg_print_command(const unsigned char * command)150 sg_print_command(const unsigned char * command)
151 {
152     int k, sz;
153     char buff[CMD_NAME_LEN];
154 
155     sg_get_command_name(command, 0, CMD_NAME_LEN, buff);
156     buff[CMD_NAME_LEN - 1] = '\0';
157 
158     pr2ws("%s [", buff);
159     if (SG_VARIABLE_LENGTH_CMD == command[0])
160         sz = command[7] + 8;
161     else
162         sz = sg_get_command_size(command[0]);
163     for (k = 0; k < sz; ++k)
164         pr2ws("%02x ", command[k]);
165     pr2ws("]\n");
166 }
167 
168 void
sg_get_scsi_status_str(int scsi_status,int buff_len,char * buff)169 sg_get_scsi_status_str(int scsi_status, int buff_len, char * buff)
170 {
171     const char * ccp = NULL;
172     bool unknown = false;
173 
174     if ((NULL == buff) || (buff_len < 1))
175         return;
176     else if (1 ==  buff_len) {
177         buff[0] = '\0';
178         return;
179     }
180     scsi_status &= 0x7e; /* sanitize as much as possible */
181     switch (scsi_status) {
182         case 0: ccp = "Good"; break;
183         case 0x2: ccp = "Check Condition"; break;
184         case 0x4: ccp = "Condition Met"; break;
185         case 0x8: ccp = "Busy"; break;
186         case 0x10: ccp = "Intermediate (obsolete)"; break;
187         case 0x14: ccp = "Intermediate-Condition Met (obsolete)"; break;
188         case 0x18: ccp = "Reservation Conflict"; break;
189         case 0x22: ccp = "Command Terminated (obsolete)"; break;
190         case 0x28: ccp = "Task set Full"; break;
191         case 0x30: ccp = "ACA Active"; break;
192         case 0x40: ccp = "Task Aborted"; break;
193         default:
194             unknown = true;
195             break;
196     }
197     if (unknown)
198         scnpr(buff, buff_len, "Unknown status [0x%x]", scsi_status);
199     else
200         scnpr(buff, buff_len, "%s", ccp);
201 }
202 
203 void
sg_print_scsi_status(int scsi_status)204 sg_print_scsi_status(int scsi_status)
205 {
206     char buff[128];
207 
208     sg_get_scsi_status_str(scsi_status, sizeof(buff) - 1, buff);
209     buff[sizeof(buff) - 1] = '\0';
210     pr2ws("%s ", buff);
211 }
212 
213 /* Get sense key from sense buffer. If successful returns a sense key value
214  * between 0 and 15. If sense buffer cannot be decode, returns -1 . */
215 int
sg_get_sense_key(const unsigned char * sbp,int sb_len)216 sg_get_sense_key(const unsigned char * sbp, int sb_len)
217 {
218     if ((NULL == sbp) || (sb_len < 2))
219         return -1;
220     switch (sbp[0] & 0x7f) {
221     case 0x70:
222     case 0x71:
223         return (sb_len < 3) ? -1 : (sbp[2] & 0xf);
224     case 0x72:
225     case 0x73:
226         return sbp[1] & 0xf;
227     default:
228         return -1;
229     }
230 }
231 
232 /* Yield string associated with sense_key value. Returns 'buff'. */
233 char *
sg_get_sense_key_str(int sense_key,int buff_len,char * buff)234 sg_get_sense_key_str(int sense_key, int buff_len, char * buff)
235 {
236     if (1 == buff_len) {
237         buff[0] = '\0';
238         return buff;
239     }
240     if ((sense_key >= 0) && (sense_key < 16))
241          scnpr(buff, buff_len, "%s", sg_lib_sense_key_desc[sense_key]);
242     else
243          scnpr(buff, buff_len, "invalid value: 0x%x", sense_key);
244     return buff;
245 }
246 
247 /* Yield string associated with ASC/ASCQ values. Returns 'buff'. */
248 char *
sg_get_asc_ascq_str(int asc,int ascq,int buff_len,char * buff)249 sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
250 {
251     int k, num, rlen;
252     bool found = false;
253     struct sg_lib_asc_ascq_t * eip;
254     struct sg_lib_asc_ascq_range_t * ei2p;
255 
256     if (1 == buff_len) {
257         buff[0] = '\0';
258         return buff;
259     }
260     for (k = 0; sg_lib_asc_ascq_range[k].text; ++k) {
261         ei2p = &sg_lib_asc_ascq_range[k];
262         if ((ei2p->asc == asc) &&
263             (ascq >= ei2p->ascq_min)  &&
264             (ascq <= ei2p->ascq_max)) {
265             found = true;
266             num = scnpr(buff, buff_len, "Additional sense: ");
267             rlen = buff_len - num;
268             scnpr(buff + num, ((rlen > 0) ? rlen : 0), ei2p->text, ascq);
269         }
270     }
271     if (found)
272         return buff;
273 
274     for (k = 0; sg_lib_asc_ascq[k].text; ++k) {
275         eip = &sg_lib_asc_ascq[k];
276         if (eip->asc == asc &&
277             eip->ascq == ascq) {
278             found = true;
279             scnpr(buff, buff_len, "Additional sense: %s", eip->text);
280         }
281     }
282     if (! found) {
283         if (asc >= 0x80)
284             scnpr(buff, buff_len, "vendor specific ASC=%02x, ASCQ=%02x "
285                   "(hex)", asc, ascq);
286         else if (ascq >= 0x80)
287             scnpr(buff, buff_len, "ASC=%02x, vendor specific qualification "
288                   "ASCQ=%02x (hex)", asc, ascq);
289         else
290             scnpr(buff, buff_len, "ASC=%02x, ASCQ=%02x (hex)", asc, ascq);
291     }
292     return buff;
293 }
294 
295 /* Attempt to find the first SCSI sense data descriptor that matches the
296  * given 'desc_type'. If found return pointer to start of sense data
297  * descriptor; otherwise (including fixed format sense data) returns NULL. */
298 const unsigned char *
sg_scsi_sense_desc_find(const unsigned char * sbp,int sb_len,int desc_type)299 sg_scsi_sense_desc_find(const unsigned char * sbp, int sb_len,
300                         int desc_type)
301 {
302     int add_sb_len, add_d_len, desc_len, k;
303     const unsigned char * descp;
304 
305     if ((sb_len < 8) || (0 == (add_sb_len = sbp[7])))
306         return NULL;
307     if ((sbp[0] < 0x72) || (sbp[0] > 0x73))
308         return NULL;
309     add_sb_len = (add_sb_len < (sb_len - 8)) ?  add_sb_len : (sb_len - 8);
310     descp = &sbp[8];
311     for (desc_len = 0, k = 0; k < add_sb_len; k += desc_len) {
312         descp += desc_len;
313         add_d_len = (k < (add_sb_len - 1)) ? descp[1]: -1;
314         desc_len = add_d_len + 2;
315         if (descp[0] == desc_type)
316             return descp;
317         if (add_d_len < 0) /* short descriptor ?? */
318             break;
319     }
320     return NULL;
321 }
322 
323 /* Returns true if valid bit set, false if valid bit clear. Irrespective the
324  * information field is written out via 'info_outp' (except when it is
325  * NULL). Handles both fixed and descriptor sense formats. */
326 bool
sg_get_sense_info_fld(const unsigned char * sbp,int sb_len,uint64_t * info_outp)327 sg_get_sense_info_fld(const unsigned char * sbp, int sb_len,
328                       uint64_t * info_outp)
329 {
330     const unsigned char * bp;
331     uint64_t ull;
332 
333     if (info_outp)
334         *info_outp = 0;
335     if (sb_len < 7)
336         return false;
337     switch (sbp[0] & 0x7f) {
338     case 0x70:
339     case 0x71:
340         if (info_outp)
341             *info_outp = sg_get_unaligned_be32(sbp + 3);
342         return !!(sbp[0] & 0x80);
343     case 0x72:
344     case 0x73:
345         bp = sg_scsi_sense_desc_find(sbp, sb_len, 0 /* info desc */);
346         if (bp && (0xa == bp[1])) {
347             ull = sg_get_unaligned_be64(bp + 4);
348             if (info_outp)
349                 *info_outp = ull;
350             return !!(bp[2] & 0x80);   /* since spc3r23 should be set */
351         } else
352             return false;
353     default:
354         return false;
355     }
356 }
357 
358 /* Returns true if fixed format or command specific information descriptor
359  * is found in the descriptor sense; else false. If available the command
360  * specific information field (4 byte integer in fixed format, 8 byte
361  * integer in descriptor format) is written out via 'cmd_spec_outp'.
362  * Handles both fixed and descriptor sense formats. */
363 bool
sg_get_sense_cmd_spec_fld(const unsigned char * sbp,int sb_len,uint64_t * cmd_spec_outp)364 sg_get_sense_cmd_spec_fld(const unsigned char * sbp, int sb_len,
365                           uint64_t * cmd_spec_outp)
366 {
367     const unsigned char * bp;
368 
369     if (cmd_spec_outp)
370         *cmd_spec_outp = 0;
371     if (sb_len < 7)
372         return false;
373     switch (sbp[0] & 0x7f) {
374     case 0x70:
375     case 0x71:
376         if (cmd_spec_outp)
377             *cmd_spec_outp = sg_get_unaligned_be32(sbp + 8);
378         return true;
379     case 0x72:
380     case 0x73:
381         bp = sg_scsi_sense_desc_find(sbp, sb_len,
382                                      1 /* command specific info desc */);
383         if (bp && (0xa == bp[1])) {
384             if (cmd_spec_outp)
385                 *cmd_spec_outp = sg_get_unaligned_be64(bp + 4);
386             return true;
387         } else
388             return false;
389     default:
390         return false;
391     }
392 }
393 
394 /* Returns true if any of the 3 bits (i.e. FILEMARK, EOM or ILI) are set.
395  * In descriptor format if the stream commands descriptor not found
396  * then returns false. Writes true or false corresponding to these bits to
397  * the last three arguments if they are non-NULL. */
398 bool
sg_get_sense_filemark_eom_ili(const unsigned char * sbp,int sb_len,bool * filemark_p,bool * eom_p,bool * ili_p)399 sg_get_sense_filemark_eom_ili(const unsigned char * sbp, int sb_len,
400                               bool * filemark_p, bool * eom_p, bool * ili_p)
401 {
402     const unsigned char * bp;
403 
404     if (sb_len < 7)
405         return false;
406     switch (sbp[0] & 0x7f) {
407     case 0x70:
408     case 0x71:
409         if (sbp[2] & 0xe0) {
410             if (filemark_p)
411                 *filemark_p = !!(sbp[2] & 0x80);
412             if (eom_p)
413                 *eom_p = !!(sbp[2] & 0x40);
414             if (ili_p)
415                 *ili_p = !!(sbp[2] & 0x20);
416             return true;
417         } else
418             return false;
419     case 0x72:
420     case 0x73:
421        /* Look for stream commands sense data descriptor */
422         bp = sg_scsi_sense_desc_find(sbp, sb_len, 4);
423         if (bp && (bp[1] >= 2)) {
424             if (bp[3] & 0xe0) {
425                 if (filemark_p)
426                     *filemark_p = !!(bp[3] & 0x80);
427                 if (eom_p)
428                     *eom_p = !!(bp[3] & 0x40);
429                 if (ili_p)
430                     *ili_p = !!(bp[3] & 0x20);
431                 return true;
432             }
433         }
434         return false;
435     default:
436         return false;
437     }
438 }
439 
440 /* Returns true if SKSV is set and sense key is NO_SENSE or NOT_READY. Also
441  * returns true if progress indication sense data descriptor found. Places
442  * progress field from sense data where progress_outp points. If progress
443  * field is not available returns false and *progress_outp is unaltered.
444  * Handles both fixed and descriptor sense formats.
445  * Hint: if true is returned *progress_outp may be multiplied by 100 then
446  * divided by 65536 to get the percentage completion. */
447 bool
sg_get_sense_progress_fld(const unsigned char * sbp,int sb_len,int * progress_outp)448 sg_get_sense_progress_fld(const unsigned char * sbp, int sb_len,
449                           int * progress_outp)
450 {
451     const unsigned char * bp;
452     int sk, sk_pr;
453 
454     if (sb_len < 7)
455         return false;
456     switch (sbp[0] & 0x7f) {
457     case 0x70:
458     case 0x71:
459         sk = (sbp[2] & 0xf);
460         if ((sb_len < 18) ||
461             ((SPC_SK_NO_SENSE != sk) && (SPC_SK_NOT_READY != sk)))
462             return false;
463         if (sbp[15] & 0x80) {        /* SKSV bit set */
464             if (progress_outp)
465                 *progress_outp = sg_get_unaligned_be16(sbp + 16);
466             return true;
467         } else
468             return false;
469     case 0x72:
470     case 0x73:
471         /* sense key specific progress (0x2) or progress descriptor (0xa) */
472         sk = (sbp[1] & 0xf);
473         sk_pr = (SPC_SK_NO_SENSE == sk) || (SPC_SK_NOT_READY == sk);
474         if (sk_pr && ((bp = sg_scsi_sense_desc_find(sbp, sb_len, 2))) &&
475             (0x6 == bp[1]) && (0x80 & bp[4])) {
476             if (progress_outp)
477                 *progress_outp = sg_get_unaligned_be16(bp + 5);
478             return true;
479         } else if (((bp = sg_scsi_sense_desc_find(sbp, sb_len, 0xa))) &&
480                    ((0x6 == bp[1]))) {
481             if (progress_outp)
482                 *progress_outp = sg_get_unaligned_be16(bp + 6);
483             return true;
484         } else
485             return false;
486     default:
487         return false;
488     }
489 }
490 
491 char *
sg_get_pdt_str(int pdt,int buff_len,char * buff)492 sg_get_pdt_str(int pdt, int buff_len, char * buff)
493 {
494     if ((pdt < 0) || (pdt > 31))
495         scnpr(buff, buff_len, "bad pdt");
496     else
497         scnpr(buff, buff_len, "%s", sg_lib_pdt_strs[pdt]);
498     return buff;
499 }
500 
501 int
sg_lib_pdt_decay(int pdt)502 sg_lib_pdt_decay(int pdt)
503 {
504     if ((pdt < 0) || (pdt > 31))
505         return 0;
506     return sg_lib_pdt_decay_arr[pdt];
507 }
508 
509 char *
sg_get_trans_proto_str(int tpi,int buff_len,char * buff)510 sg_get_trans_proto_str(int tpi, int buff_len, char * buff)
511 {
512     if ((tpi < 0) || (tpi > 15))
513         scnpr(buff, buff_len, "bad tpi");
514     else
515         scnpr(buff, buff_len, "%s", sg_lib_transport_proto_strs[tpi]);
516     return buff;
517 }
518 
519 #define TRANSPORT_ID_MIN_LEN 24
520 
521 char *
sg_decode_transportid_str(const char * lip,unsigned char * bp,int bplen,bool only_one,int blen,char * b)522 sg_decode_transportid_str(const char * lip, unsigned char * bp, int bplen,
523                           bool only_one, int blen, char * b)
524 {
525     int proto_id, num, k, n, normal_len, tpid_format;
526     uint64_t ull;
527     int bump;
528 
529     if ((NULL == b) || (blen < 1))
530         return b;
531     else if (1 == blen) {
532         b[0] = '\0';
533         return b;
534     }
535     if (NULL == lip)
536         lip = "";
537     bump = TRANSPORT_ID_MIN_LEN; /* should be overwritten in all loop paths */
538     for (k = 0, n = 0; bplen > 0; ++k, bp += bump, bplen -= bump) {
539         if ((k > 0) && only_one)
540             break;
541         if ((bplen < 24) || (0 != (bplen % 4)))
542             n += scnpr(b + n, blen - n, "%sTransport Id short or not "
543                        "multiple of 4 [length=%d]:\n", lip, blen);
544         else
545             n += scnpr(b + n, blen - n, "%sTransport Id of initiator:\n",
546                        lip);
547         tpid_format = ((bp[0] >> 6) & 0x3);
548         proto_id = (bp[0] & 0xf);
549         normal_len = (bplen > TRANSPORT_ID_MIN_LEN) ?
550                                 TRANSPORT_ID_MIN_LEN : bplen;
551         switch (proto_id) {
552         case TPROTO_FCP: /* Fibre channel */
553             n += scnpr(b + n, blen - n, "%s  FCP-2 World Wide Name:\n", lip);
554             if (0 != tpid_format)
555                 n += scnpr(b + n, blen - n, "%s  [Unexpected TPID format: "
556                            "%d]\n", lip, tpid_format);
557             n += hex2str(bp + 8, 8, lip, 1, blen - n, b + n);
558             bump = TRANSPORT_ID_MIN_LEN;
559             break;
560         case TPROTO_SPI:        /* Scsi Parallel Interface, obsolete */
561             n += scnpr(b + n, blen - n, "%s  Parallel SCSI initiator SCSI "
562                        "address: 0x%x\n", lip, sg_get_unaligned_be16(bp + 2));
563             if (0 != tpid_format)
564                 n += scnpr(b + n, blen - n, "%s  [Unexpected TPID format: "
565                            "%d]\n", lip, tpid_format);
566             n += scnpr(b + n, blen - n, "%s  relative port number (of "
567                        "corresponding target): 0x%x\n", lip,
568                        sg_get_unaligned_be16(bp + 6));
569             bump = TRANSPORT_ID_MIN_LEN;
570             break;
571         case TPROTO_SSA:
572             n += scnpr(b + n, blen - n, "%s  SSA (transport id not "
573                        "defined):\n", lip);
574             n += scnpr(b + n, blen - n, "%s  TPID format: %d\n", lip,
575                        tpid_format);
576             n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
577             bump = TRANSPORT_ID_MIN_LEN;
578             break;
579         case TPROTO_1394: /* IEEE 1394 */
580             n += scnpr(b + n, blen - n, "%s  IEEE 1394 EUI-64 name:\n", lip);
581             if (0 != tpid_format)
582                 n += scnpr(b + n, blen - n, "%s  [Unexpected TPID format: "
583                            "%d]\n", lip, tpid_format);
584             n += hex2str(&bp[8], 8, lip, 1, blen - n, b + n);
585             bump = TRANSPORT_ID_MIN_LEN;
586             break;
587         case TPROTO_SRP:        /* SCSI over RDMA */
588             n += scnpr(b + n, blen - n, "%s  RDMA initiator port "
589                        "identifier:\n", lip);
590             if (0 != tpid_format)
591                 n += scnpr(b + n, blen - n, "%s  [Unexpected TPID format: "
592                            "%d]\n", lip, tpid_format);
593             n += hex2str(bp + 8, 16, lip, 1, blen - n, b + n);
594             bump = TRANSPORT_ID_MIN_LEN;
595             break;
596         case TPROTO_ISCSI:
597             n += scnpr(b + n, blen - n, "%s  iSCSI ", lip);
598             num = sg_get_unaligned_be16(bp + 2);
599             if (0 == tpid_format)
600                 n += scnpr(b + n, blen - n, "name: %.*s\n", num, &bp[4]);
601             else if (1 == tpid_format)
602                 n += scnpr(b + n, blen - n, "world wide unique port id: "
603                            "%.*s\n", num, &bp[4]);
604             else {
605                 n += scnpr(b + n, blen - n, "  [Unexpected TPID format: "
606                            "%d]\n", tpid_format);
607                 n += hex2str(bp, num + 4, lip, 0, blen - n, b + n);
608             }
609             bump = (((num + 4) < TRANSPORT_ID_MIN_LEN) ?
610                          TRANSPORT_ID_MIN_LEN : num + 4);
611             break;
612         case TPROTO_SAS:
613             ull = sg_get_unaligned_be64(bp + 4);
614             n += scnpr(b + n, blen - n, "%s  SAS address: 0x%" PRIx64 "\n",
615                        lip, ull);
616             if (0 != tpid_format)
617                 n += scnpr(b + n, blen - n, "%s  [Unexpected TPID format: "
618                            "%d]\n", lip, tpid_format);
619             bump = TRANSPORT_ID_MIN_LEN;
620             break;
621         case TPROTO_ADT:        /* no TransportID defined by T10 yet */
622             n += scnpr(b + n, blen - n, "%s  ADT:\n", lip);
623             n += scnpr(b + n, blen - n, "%s  TPID format: %d\n", lip,
624                        tpid_format);
625             n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
626             bump = TRANSPORT_ID_MIN_LEN;
627             break;
628         case TPROTO_ATA:        /* no TransportID defined by T10 yet */
629             n += scnpr(b + n, blen - n, "%s  ATAPI:\n", lip);
630             n += scnpr(b + n, blen - n, "%s  TPID format: %d\n", lip,
631                        tpid_format);
632             n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
633             bump = TRANSPORT_ID_MIN_LEN;
634             break;
635         case TPROTO_UAS:        /* no TransportID defined by T10 yet */
636             n += scnpr(b + n, blen - n, "%s  UAS:\n", lip);
637             n += scnpr(b + n, blen - n, "%s  TPID format: %d\n", lip,
638                        tpid_format);
639             n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
640             bump = TRANSPORT_ID_MIN_LEN;
641             break;
642         case TPROTO_SOP:
643             n += scnpr(b + n, blen - n, "%s  SOP ", lip);
644             num = sg_get_unaligned_be16(bp + 2);
645             if (0 == tpid_format)
646                 n += scnpr(b + n, blen - n, "Routing ID: 0x%x\n", num);
647             else {
648                 n += scnpr(b + n, blen - n, "  [Unexpected TPID format: "
649                            "%d]\n", tpid_format);
650                 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
651             }
652             bump = TRANSPORT_ID_MIN_LEN;
653             break;
654         case TPROTO_PCIE:       /* no TransportID defined by T10 yet */
655             n += scnpr(b + n, blen - n, "%s  PCIE:\n", lip);
656             n += scnpr(b + n, blen - n, "%s  TPID format: %d\n", lip,
657                        tpid_format);
658             n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
659             bump = TRANSPORT_ID_MIN_LEN;
660             break;
661         case TPROTO_NONE:       /* no TransportID defined by T10 */
662             n += scnpr(b + n, blen - n, "%s  No specified protocol\n", lip);
663             /* n += hex2str(bp, ((bplen > 24) ? 24 : bplen),
664              *                 lip, 0, blen - n, b + n); */
665             bump = TRANSPORT_ID_MIN_LEN;
666             break;
667         default:
668             n += scnpr(b + n, blen - n, "%s  unknown protocol id=0x%x  "
669                        "TPID format=%d\n", lip, proto_id, tpid_format);
670             n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
671             bump = TRANSPORT_ID_MIN_LEN;
672             break;
673         }
674     }
675     return b;
676 }
677 
678 
679 static const char * desig_code_set_str_arr[] =
680 {
681     "Reserved [0x0]",
682     "Binary",
683     "ASCII",
684     "UTF-8",
685     "Reserved [0x4]", "Reserved [0x5]", "Reserved [0x6]", "Reserved [0x7]",
686     "Reserved [0x8]", "Reserved [0x9]", "Reserved [0xa]", "Reserved [0xb]",
687     "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]",
688 };
689 
690 const char *
sg_get_desig_code_set_str(int val)691 sg_get_desig_code_set_str(int val)
692 {
693     if ((val >= 0) && (val < 16))
694         return desig_code_set_str_arr[val];
695     else
696         return NULL;
697 }
698 
699 static const char * desig_assoc_str_arr[] =
700 {
701     "Addressed logical unit",
702     "Target port",      /* that received request; unless SCSI ports VPD */
703     "Target device that contains addressed lu",
704     "Reserved [0x3]",
705 };
706 
707 const char *
sg_get_desig_assoc_str(int val)708 sg_get_desig_assoc_str(int val)
709 {
710     if ((val >= 0) && (val < 4))
711         return desig_assoc_str_arr[val];
712     else
713         return NULL;
714 }
715 
716 static const char * desig_type_str_arr[] =
717 {
718     "vendor specific [0x0]",
719     "T10 vendor identification",
720     "EUI-64 based",
721     "NAA",
722     "Relative target port",
723     "Target port group",        /* spc4r09: _primary_ target port group */
724     "Logical unit group",
725     "MD5 logical unit identifier",
726     "SCSI name string",
727     "Protocol specific port identifier",        /* spc4r36 */
728     "UUID identifier",          /* spc5r08 */
729     "Reserved [0xb]",
730     "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]",
731 };
732 
733 const char *
sg_get_desig_type_str(int val)734 sg_get_desig_type_str(int val)
735 {
736     if ((val >= 0) && (val < 16))
737         return desig_type_str_arr[val];
738     else
739         return NULL;
740 }
741 
742 int
sg_get_designation_descriptor_str(const char * lip,const unsigned char * ddp,int dd_len,bool print_assoc,bool do_long,int blen,char * b)743 sg_get_designation_descriptor_str(const char * lip, const unsigned char * ddp,
744                                   int dd_len, bool print_assoc, bool do_long,
745                                   int blen, char * b)
746 {
747     int m, p_id, piv, c_set, assoc, desig_type, ci_off, c_id, d_id, naa;
748     int vsi, k, n, dlen;
749     const unsigned char * ip;
750     uint64_t vsei;
751     uint64_t id_ext;
752     char e[64];
753     const char * cp;
754 
755     n = 0;
756     if (NULL == lip)
757         lip = "";
758     if (dd_len < 4) {
759         n += scnpr(b + n, blen - n, "%sdesignator desc too short: got "
760                    "length of %d want 4 or more\n", lip, dd_len);
761         return n;
762     }
763     dlen = ddp[3];
764     if (dlen > (dd_len - 4)) {
765         n += scnpr(b + n, blen - n, "%sdesignator too long: says it is %d "
766                    "bytes, but given %d bytes\n", lip, dlen, dd_len - 4);
767         return n;
768     }
769     ip = ddp + 4;
770     p_id = ((ddp[0] >> 4) & 0xf);
771     c_set = (ddp[0] & 0xf);
772     piv = ((ddp[1] & 0x80) ? 1 : 0);
773     assoc = ((ddp[1] >> 4) & 0x3);
774     desig_type = (ddp[1] & 0xf);
775     if (print_assoc && ((cp = sg_get_desig_assoc_str(assoc))))
776         n += scnpr(b + n, blen - n, "%s  %s:\n", lip, cp);
777     n += scnpr(b + n, blen - n, "%s    designator type: ", lip);
778     cp = sg_get_desig_type_str(desig_type);
779     if (cp)
780         n += scnpr(b + n, blen - n, "%s", cp);
781     n += scnpr(b + n, blen - n, ",  code set: ");
782     cp = sg_get_desig_code_set_str(c_set);
783     if (cp)
784         n += scnpr(b + n, blen - n, "%s", cp);
785     n += scnpr(b + n, blen - n, "\n");
786     if (piv && ((1 == assoc) || (2 == assoc)))
787         n += scnpr(b + n, blen - n, "%s     transport: %s\n", lip,
788                    sg_get_trans_proto_str(p_id, sizeof(e), e));
789     /* printf("    associated with the %s\n", sdparm_assoc_arr[assoc]); */
790     switch (desig_type) {
791     case 0: /* vendor specific */
792         k = 0;
793         if ((1 == c_set) || (2 == c_set)) { /* ASCII or UTF-8 */
794             for (k = 0; (k < dlen) && my_isprint(ip[k]); ++k)
795                 ;
796             if (k >= dlen)
797                 k = 1;
798         }
799         if (k)
800             n += scnpr(b + n, blen - n, "%s      vendor specific: %.*s\n",
801                        lip, dlen, ip);
802         else {
803             n += scnpr(b + n, blen - n, "%s      vendor specific:\n", lip);
804             n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
805         }
806         break;
807     case 1: /* T10 vendor identification */
808         n += scnpr(b + n, blen - n, "%s      vendor id: %.8s\n", lip, ip);
809         if (dlen > 8) {
810             if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
811                 n += scnpr(b + n, blen - n, "%s      vendor specific: "
812                            "%.*s\n", lip, dlen - 8, ip + 8);
813             } else {
814                 n += scnpr(b + n, blen - n, "%s      vendor specific: 0x",
815                            lip);
816                 for (m = 8; m < dlen; ++m)
817                     n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
818                 n += scnpr(b + n, blen - n, "\n");
819             }
820         }
821         break;
822     case 2: /* EUI-64 based */
823         if (! do_long) {
824             if ((8 != dlen) && (12 != dlen) && (16 != dlen)) {
825                 n += scnpr(b + n, blen - n, "%s      << expect 8, 12 and 16 "
826                            "byte EUI, got %d >>\n", lip, dlen);
827                  n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
828                 break;
829             }
830             n += scnpr(b + n, blen - n, "%s      0x", lip);
831             for (m = 0; m < dlen; ++m)
832                 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
833             n += scnpr(b + n, blen - n, "\n");
834             break;
835         }
836         n += scnpr(b + n, blen - n, "%s      EUI-64 based %d byte "
837                    "identifier\n", lip, dlen);
838         if (1 != c_set) {
839             n += scnpr(b + n, blen - n, "%s      << expected binary code_set "
840                        "(1) >>\n", lip);
841             n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
842             break;
843         }
844         ci_off = 0;
845         if (16 == dlen) {
846             ci_off = 8;
847             id_ext = sg_get_unaligned_be64(ip);
848             n += scnpr(b + n, blen - n, "%s      Identifier extension: 0x%"
849                        PRIx64 "\n", lip, id_ext);
850         } else if ((8 != dlen) && (12 != dlen)) {
851             n += scnpr(b + n, blen - n, "%s      << can only decode 8, 12 "
852                        "and 16 byte ids >>\n", lip);
853             n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
854             break;
855         }
856         c_id = sg_get_unaligned_be24(ip + ci_off);
857         n += scnpr(b + n, blen - n, "%s      IEEE Company_id: 0x%x\n", lip,
858                    c_id);
859         vsei = 0;
860         for (m = 0; m < 5; ++m) {
861             if (m > 0)
862                 vsei <<= 8;
863             vsei |= ip[ci_off + 3 + m];
864         }
865         n += scnpr(b + n, blen - n, "%s      Vendor Specific Extension "
866                    "Identifier: 0x%" PRIx64 "\n", lip, vsei);
867         if (12 == dlen) {
868             d_id = sg_get_unaligned_be32(ip + 8);
869             n += scnpr(b + n, blen - n, "%s      Directory ID: 0x%x\n", lip,
870                        d_id);
871         }
872         break;
873     case 3: /* NAA <n> */
874         if (1 != c_set) {
875             n += scnpr(b + n, blen - n, "%s      << unexpected code set %d "
876                        "for NAA >>\n", lip, c_set);
877             n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
878             break;
879         }
880         naa = (ip[0] >> 4) & 0xff;
881         switch (naa) {
882         case 2:         /* NAA 2: IEEE Extended */
883             if (8 != dlen) {
884                 n += scnpr(b + n, blen - n, "%s      << unexpected NAA 2 "
885                            "identifier length: 0x%x >>\n", lip, dlen);
886                 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
887                 break;
888             }
889             d_id = (((ip[0] & 0xf) << 8) | ip[1]);
890             c_id = sg_get_unaligned_be24(ip + 2);
891             vsi = sg_get_unaligned_be24(ip + 5);
892             if (do_long) {
893                 n += scnpr(b + n, blen - n, "%s      NAA 2, vendor specific "
894                            "identifier A: 0x%x\n", lip, d_id);
895                 n += scnpr(b + n, blen - n, "%s      IEEE Company_id: 0x%x\n",
896                            lip, c_id);
897                 n += scnpr(b + n, blen - n, "%s      vendor specific "
898                            "identifier B: 0x%x\n", lip, vsi);
899                 n += scnpr(b + n, blen - n, "%s      [0x", lip);
900                 for (m = 0; m < 8; ++m)
901                     n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
902                 n += scnpr(b + n, blen - n, "]\n");
903             }
904             n += scnpr(b + n, blen - n, "%s      0x", lip);
905             for (m = 0; m < 8; ++m)
906                 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
907             n += scnpr(b + n, blen - n, "\n");
908             break;
909         case 3:         /* NAA 3: Locally assigned */
910             if (8 != dlen) {
911                 n += scnpr(b + n, blen - n, "%s      << unexpected NAA 3 "
912                            "identifier length: 0x%x >>\n", lip, dlen);
913                 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
914                 break;
915             }
916             if (do_long)
917                 n += scnpr(b + n, blen - n, "%s      NAA 3, Locally "
918                            "assigned:\n", lip);
919             n += scnpr(b + n, blen - n, "%s      0x", lip);
920             for (m = 0; m < 8; ++m)
921                 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
922             n += scnpr(b + n, blen - n, "\n");
923             break;
924         case 5:         /* NAA 5: IEEE Registered */
925             if (8 != dlen) {
926                 n += scnpr(b + n, blen - n, "%s      << unexpected NAA 5 "
927                            "identifier length: 0x%x >>\n", lip, dlen);
928                 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
929                 break;
930             }
931             c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
932                     (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
933             vsei = ip[3] & 0xf;
934             for (m = 1; m < 5; ++m) {
935                 vsei <<= 8;
936                 vsei |= ip[3 + m];
937             }
938             if (do_long) {
939                 n += scnpr(b + n, blen - n, "%s      NAA 5, IEEE "
940                            "Company_id: 0x%x\n", lip, c_id);
941                 n += scnpr(b + n, blen - n, "%s      Vendor Specific "
942                            "Identifier: 0x%" PRIx64 "\n", lip, vsei);
943                 n += scnpr(b + n, blen - n, "%s      [0x", lip);
944                 for (m = 0; m < 8; ++m)
945                     n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
946                 n += scnpr(b + n, blen - n, "]\n");
947             } else {
948                 n += scnpr(b + n, blen - n, "%s      0x", lip);
949                 for (m = 0; m < 8; ++m)
950                     n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
951                 n += scnpr(b + n, blen - n, "\n");
952             }
953             break;
954         case 6:         /* NAA 6: IEEE Registered extended */
955             if (16 != dlen) {
956                 n += scnpr(b + n, blen - n, "%s      << unexpected NAA 6 "
957                            "identifier length: 0x%x >>\n", lip, dlen);
958                 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
959                 break;
960             }
961             c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
962                     (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
963             vsei = ip[3] & 0xf;
964             for (m = 1; m < 5; ++m) {
965                 vsei <<= 8;
966                 vsei |= ip[3 + m];
967             }
968             if (do_long) {
969                 n += scnpr(b + n, blen - n, "%s      NAA 6, IEEE "
970                            "Company_id: 0x%x\n", lip, c_id);
971                 n += scnpr(b + n, blen - n, "%s      Vendor Specific "
972                            "Identifier: 0x%" PRIx64 "\n", lip, vsei);
973                 vsei = sg_get_unaligned_be64(ip + 8);
974                 n += scnpr(b + n, blen - n, "%s      Vendor Specific "
975                            "Identifier Extension: 0x%" PRIx64 "\n", lip,
976                                  vsei);
977                 n += scnpr(b + n, blen - n, "%s      [0x", lip);
978                 for (m = 0; m < 16; ++m)
979                     n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
980                 n += scnpr(b + n, blen - n, "]\n");
981             } else {
982                 n += scnpr(b + n, blen - n, "%s      0x", lip);
983                 for (m = 0; m < 16; ++m)
984                     n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
985                 n += scnpr(b + n, blen - n, "\n");
986             }
987             break;
988         default:
989             n += scnpr(b + n, blen - n, "%s      << unexpected NAA [0x%x] "
990                        ">>\n", lip, naa);
991             n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
992             break;
993         }
994         break;
995     case 4: /* Relative target port */
996         if ((1 != c_set) || (1 != assoc) || (4 != dlen)) {
997             n += scnpr(b + n, blen - n, "%s      << expected binary "
998                        "code_set, target port association, length 4 >>\n",
999                        lip);
1000             n += hex2str(ip, dlen, "", 1, blen - n, b + n);
1001             break;
1002         }
1003         d_id = sg_get_unaligned_be16(ip + 2);
1004         n += scnpr(b + n, blen - n, "%s      Relative target port: 0x%x\n",
1005                    lip, d_id);
1006         break;
1007     case 5: /* (primary) Target port group */
1008         if ((1 != c_set) || (1 != assoc) || (4 != dlen)) {
1009             n += scnpr(b + n, blen - n, "%s      << expected binary "
1010                        "code_set, target port association, length 4 >>\n",
1011                        lip);
1012             n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1013             break;
1014         }
1015         d_id = sg_get_unaligned_be16(ip + 2);
1016         n += scnpr(b + n, blen - n, "%s      Target port group: 0x%x\n", lip,
1017                    d_id);
1018         break;
1019     case 6: /* Logical unit group */
1020         if ((1 != c_set) || (0 != assoc) || (4 != dlen)) {
1021             n += scnpr(b + n, blen - n, "%s      << expected binary "
1022                        "code_set, logical unit association, length 4 >>\n",
1023                        lip);
1024             n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1025             break;
1026         }
1027         d_id = sg_get_unaligned_be16(ip + 2);
1028         n += scnpr(b + n, blen - n, "%s      Logical unit group: 0x%x\n", lip,
1029                    d_id);
1030         break;
1031     case 7: /* MD5 logical unit identifier */
1032         if ((1 != c_set) || (0 != assoc)) {
1033             n += scnpr(b + n, blen - n, "%s      << expected binary "
1034                        "code_set, logical unit association >>\n", lip);
1035             n += hex2str(ip, dlen, "", 1, blen - n, b + n);
1036             break;
1037         }
1038         n += scnpr(b + n, blen - n, "%s      MD5 logical unit identifier:\n",
1039                    lip);
1040         n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1041         break;
1042     case 8: /* SCSI name string */
1043         if (3 != c_set) {       /* accept ASCII as subset of UTF-8 */
1044             if (2 == c_set) {
1045                 if (do_long)
1046                     n += scnpr(b + n, blen - n, "%s      << expected UTF-8, "
1047                                "use ASCII >>\n", lip);
1048             } else {
1049                 n += scnpr(b + n, blen - n, "%s      << expected UTF-8 "
1050                            "code_set >>\n", lip);
1051                 n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
1052                 break;
1053             }
1054         }
1055         n += scnpr(b + n, blen - n, "%s      SCSI name string:\n", lip);
1056         /* does %s print out UTF-8 ok??
1057          * Seems to depend on the locale. Looks ok here with my
1058          * locale setting: en_AU.UTF-8
1059          */
1060         n += scnpr(b + n, blen - n, "%s      %.*s\n", lip, dlen,
1061                    (const char *)ip);
1062         break;
1063     case 9: /* Protocol specific port identifier */
1064         /* added in spc4r36, PIV must be set, proto_id indicates */
1065         /* whether UAS (USB) or SOP (PCIe) or ... */
1066         if (! piv)
1067             n += scnpr(b + n, blen - n, " %s      >>>> Protocol specific "
1068                        "port identifier expects protocol\n"
1069                        "%s           identifier to be valid and it is not\n",
1070                        lip, lip);
1071         if (TPROTO_UAS == p_id) {
1072             n += scnpr(b + n, blen - n, "%s      USB device address: 0x%x\n",
1073                        lip, 0x7f & ip[0]);
1074             n += scnpr(b + n, blen - n, "%s      USB interface number: "
1075                        "0x%x\n", lip, ip[2]);
1076         } else if (TPROTO_SOP == p_id) {
1077             n += scnpr(b + n, blen - n, "%s      PCIe routing ID, bus "
1078                        "number: 0x%x\n", lip, ip[0]);
1079             n += scnpr(b + n, blen - n, "%s          function number: 0x%x\n",
1080                        lip, ip[1]);
1081             n += scnpr(b + n, blen - n, "%s          [or device number: "
1082                        "0x%x, function number: 0x%x]\n", lip,
1083                        (0x1f & (ip[1] >> 3)), 0x7 & ip[1]);
1084         } else
1085             n += scnpr(b + n, blen - n, "%s      >>>> unexpected protocol "
1086                        "indentifier: %s\n%s           with Protocol specific "
1087                        "port identifier\n", lip,
1088                        sg_get_trans_proto_str(p_id, sizeof(e), e), lip);
1089         break;
1090     case 0xa: /* UUID identifier */
1091         if (1 != c_set) {
1092             n += scnpr(b + n, blen - n, "%s      << expected binary "
1093                        "code_set >>\n", lip);
1094             n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
1095             break;
1096         }
1097         if ((1 != ((ip[0] >> 4) & 0xf)) || (18 != dlen)) {
1098             n += scnpr(b + n, blen - n, "%s      << expected locally "
1099                        "assigned UUID, 16 bytes long >>\n", lip);
1100             n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
1101             break;
1102         }
1103         n += scnpr(b + n, blen - n, "%s      Locally assigned UUID: ", lip);
1104         for (m = 0; m < 16; ++m) {
1105             if ((4 == m) || (6 == m) || (8 == m) || (10 == m))
1106                 n += scnpr(b + n, blen - n, "-");
1107             n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[2 + m]);
1108         }
1109         n += scnpr(b + n, blen - n, "\n");
1110         if (do_long) {
1111             n += scnpr(b + n, blen - n, "%s      [0x", lip);
1112             for (m = 0; m < 16; ++m)
1113                 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[2 + m]);
1114             n += scnpr(b + n, blen - n, "]\n");
1115         }
1116         break;
1117     default: /* reserved */
1118         n += scnpr(b + n, blen - n, "%s      reserved designator=0x%x\n", lip,
1119                    desig_type);
1120         n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1121         break;
1122     }
1123     return n;
1124 }
1125 
1126 static int
decode_sks(const char * lip,const unsigned char * descp,int add_d_len,int sense_key,bool * processedp,int blen,char * b)1127 decode_sks(const char * lip, const unsigned char * descp, int add_d_len,
1128            int sense_key, bool * processedp, int blen, char * b)
1129 {
1130     int progress, pr, rem, n;
1131 
1132     n = 0;
1133     if (NULL == lip)
1134         lip = "";
1135     switch (sense_key) {
1136     case SPC_SK_ILLEGAL_REQUEST:
1137         if (add_d_len < 6) {
1138             n += scnpr(b + n, blen - n, "Field pointer: ");
1139             goto too_short;
1140         }
1141         /* abbreviate to fit on one line */
1142         n += scnpr(b + n, blen - n, "Field pointer:\n");
1143         n += scnpr(b + n, blen - n, "%s        Error in %s: byte %d", lip,
1144                    (descp[4] & 0x40) ? "Command" :
1145                                                   "Data parameters",
1146                          sg_get_unaligned_be16(descp + 5));
1147         if (descp[4] & 0x08) {
1148             n += scnpr(b + n, blen - n, " bit %d\n", descp[4] & 0x07);
1149         } else
1150             n += scnpr(b + n, blen - n, "\n");
1151         break;
1152     case SPC_SK_HARDWARE_ERROR:
1153     case SPC_SK_MEDIUM_ERROR:
1154     case SPC_SK_RECOVERED_ERROR:
1155         n += scnpr(b + n, blen - n, "Actual retry count: ");
1156         if (add_d_len < 6)
1157             goto too_short;
1158         n += scnpr(b + n, blen - n,"%u\n", sg_get_unaligned_be16(descp + 5));
1159         break;
1160     case SPC_SK_NO_SENSE:
1161     case SPC_SK_NOT_READY:
1162         n += scnpr(b + n, blen - n, "Progress indication: ");
1163         if (add_d_len < 6)
1164             goto too_short;
1165         progress = sg_get_unaligned_be16(descp + 5);
1166         pr = (progress * 100) / 65536;
1167         rem = ((progress * 100) % 65536) / 656;
1168         n += scnpr(b + n, blen - n, "%d.%02d%%\n", pr, rem);
1169         break;
1170     case SPC_SK_COPY_ABORTED:
1171         n += scnpr(b + n, blen - n, "Segment pointer:\n");
1172         if (add_d_len < 6)
1173             goto too_short;
1174         n += scnpr(b + n, blen - n, "%s        Relative to start of %s, byte "
1175                    "%d", lip, (descp[4] & 0x20) ? "segment descriptor" :
1176                                                   "parameter list",
1177                    sg_get_unaligned_be16(descp + 5));
1178         if (descp[4] & 0x08)
1179             n += scnpr(b + n, blen - n, " bit %d\n", descp[4] & 0x07);
1180         else
1181             n += scnpr(b + n, blen - n, "\n");
1182         break;
1183     case SPC_SK_UNIT_ATTENTION:
1184         n += scnpr(b + n, blen - n, "Unit attention condition queue:\n");
1185         n += scnpr(b + n, blen - n, "%s        overflow flag is %d\n", lip,
1186                    !!(descp[4] & 0x1));
1187         break;
1188     default:
1189         n += scnpr(b + n, blen - n, "Sense_key: 0x%x unexpected\n",
1190                    sense_key);
1191         *processedp = false;
1192         break;
1193     }
1194     return n;
1195 
1196 too_short:
1197     n += scnpr(b + n, blen - n, "%s\n", "   >> descriptor too short");
1198     *processedp = false;
1199     return n;
1200 }
1201 
1202 #define TPGS_STATE_OPTIMIZED 0x0
1203 #define TPGS_STATE_NONOPTIMIZED 0x1
1204 #define TPGS_STATE_STANDBY 0x2
1205 #define TPGS_STATE_UNAVAILABLE 0x3
1206 #define TPGS_STATE_OFFLINE 0xe
1207 #define TPGS_STATE_TRANSITIONING 0xf
1208 
1209 static int
decode_tpgs_state(int st,char * b,int blen)1210 decode_tpgs_state(int st, char * b, int blen)
1211 {
1212     switch (st) {
1213     case TPGS_STATE_OPTIMIZED:
1214         return scnpr(b, blen, "active/optimized");
1215     case TPGS_STATE_NONOPTIMIZED:
1216         return scnpr(b, blen, "active/non optimized");
1217     case TPGS_STATE_STANDBY:
1218         return scnpr(b, blen, "standby");
1219     case TPGS_STATE_UNAVAILABLE:
1220         return scnpr(b, blen, "unavailable");
1221     case TPGS_STATE_OFFLINE:
1222         return scnpr(b, blen, "offline");
1223     case TPGS_STATE_TRANSITIONING:
1224         return scnpr(b, blen, "transitioning between states");
1225     default:
1226         return scnpr(b, blen, "unknown: 0x%x", st);
1227     }
1228 }
1229 
1230 static int
uds_referral_descriptor_str(char * b,int blen,const unsigned char * dp,int alen,const char * lip)1231 uds_referral_descriptor_str(char * b, int blen, const unsigned char * dp,
1232                             int alen, const char * lip)
1233 {
1234     int n = 0;
1235     int dlen = alen - 2;
1236     int k, j, g, f, tpgd;
1237     const unsigned char * tp;
1238     uint64_t ull;
1239     char c[40];
1240 
1241     if (NULL == lip)
1242         lip = "";
1243     n += scnpr(b + n, blen - n, "%s   Not all referrals: %d\n", lip,
1244                !!(dp[2] & 0x1));
1245     dp += 4;
1246     for (k = 0, f = 1; (k + 4) < dlen; k += g, dp += g, ++f) {
1247         tpgd = dp[3];
1248         g = (tpgd * 4) + 20;
1249         n += scnpr(b + n, blen - n, "%s    Descriptor %d\n", lip, f);
1250         if ((k + g) > dlen) {
1251             n += scnpr(b + n, blen - n, "%s      truncated descriptor, "
1252                        "stop\n", lip);
1253             return n;
1254         }
1255         ull = sg_get_unaligned_be64(dp + 4);
1256         n += scnpr(b + n, blen - n, "%s      first uds LBA: 0x%" PRIx64 "\n",
1257                    lip, ull);
1258         ull = sg_get_unaligned_be64(dp + 12);
1259         n += scnpr(b + n, blen - n, "%s      last uds LBA:  0x%" PRIx64 "\n",
1260                    lip, ull);
1261         for (j = 0; j < tpgd; ++j) {
1262             tp = dp + 20 + (j * 4);
1263             decode_tpgs_state(tp[0] & 0xf, c, sizeof(c));
1264             n += scnpr(b + n, blen - n, "%s        tpg: %d  state: %s\n",
1265                        lip, sg_get_unaligned_be16(tp + 2), c);
1266         }
1267     }
1268     return n;
1269 }
1270 
1271 static const char * dd_usage_reason_str_arr[] = {
1272     "Unknown",
1273     "resend this and further commands to:",
1274     "resend this command to:",
1275     "new subsiduary lu added to this administrative lu:",
1276     "administrative lu associated with a preferred binding:",
1277    };
1278 
1279 
1280 /* Decode descriptor format sense descriptors (assumes sense buffer is
1281  * in descriptor format) */
1282 int
sg_get_sense_descriptors_str(const char * lip,const unsigned char * sbp,int sb_len,int blen,char * b)1283 sg_get_sense_descriptors_str(const char * lip, const unsigned char * sbp,
1284                              int sb_len, int blen, char * b)
1285 {
1286     int add_sb_len, add_d_len, desc_len, k, j, sense_key;
1287     int n, progress, pr, rem;
1288     bool processed;
1289     const unsigned char * descp;
1290     const char * dtsp = "   >> descriptor too short";
1291     const char * eccp = "Extended copy command";
1292     const char * ddp = "destination device";
1293     char z[64];
1294 
1295     if ((NULL == b) || (blen <= 0))
1296         return 0;
1297     b[0] = '\0';
1298     if (lip)
1299         scnpr(z, sizeof(z), "%.60s  ", lip);
1300     else
1301         scnpr(z, sizeof(z), "  ");
1302     if ((sb_len < 8) || (0 == (add_sb_len = sbp[7])))
1303         return 0;
1304     add_sb_len = (add_sb_len < (sb_len - 8)) ? add_sb_len : (sb_len - 8);
1305     sense_key = (sbp[1] & 0xf);
1306 
1307     for (descp = (sbp + 8), k = 0, n = 0;
1308          (k < add_sb_len) && (n < blen);
1309          k += desc_len, descp += desc_len) {
1310         add_d_len = (k < (add_sb_len - 1)) ? descp[1] : -1;
1311         if ((k + add_d_len + 2) > add_sb_len)
1312             add_d_len = add_sb_len - k - 2;
1313         desc_len = add_d_len + 2;
1314         n += scnpr(b + n, blen - n, "%s  Descriptor type: ", lip);
1315         processed = true;
1316         switch (descp[0]) {
1317         case 0:
1318             n += scnpr(b + n, blen - n, "Information: ");
1319             if ((add_d_len >= 10) && (0x80 & descp[2])) {
1320                 n += scnpr(b + n, blen - n, "0x");
1321                 for (j = 0; j < 8; ++j)
1322                     n += scnpr(b + n, blen - n, "%02x", descp[4 + j]);
1323                 n += scnpr(b + n, blen - n, "\n");
1324             } else {
1325                 n += scnpr(b + n, blen - n, "%s\n", dtsp);
1326                 processed = false;
1327             }
1328             break;
1329         case 1:
1330             n += scnpr(b + n, blen - n, "Command specific: ");
1331             if (add_d_len >= 10) {
1332                 n += scnpr(b + n, blen - n, "0x");
1333                 for (j = 0; j < 8; ++j)
1334                     n += scnpr(b + n, blen - n, "%02x", descp[4 + j]);
1335                 n += scnpr(b + n, blen - n, "\n");
1336             } else {
1337                 n += scnpr(b + n, blen - n, "%s\n", dtsp);
1338                 processed = false;
1339             }
1340             break;
1341         case 2:         /* Sense Key Specific */
1342             n += scnpr(b + n, blen - n, "Sense key specific: ");
1343             n += decode_sks(lip, descp, add_d_len, sense_key, &processed,
1344                             blen - n, b + n);
1345             break;
1346         case 3:
1347             n += scnpr(b + n, blen - n, "Field replaceable unit code: ");
1348             if (add_d_len >= 2)
1349                 n += scnpr(b + n, blen - n, "0x%x\n", descp[3]);
1350             else {
1351                 n += scnpr(b + n, blen - n, "%s\n", dtsp);
1352                 processed = false;
1353             }
1354             break;
1355         case 4:
1356             n += scnpr(b + n, blen - n, "Stream commands: ");
1357             if (add_d_len >= 2) {
1358                 if (descp[3] & 0x80)
1359                     n += scnpr(b + n, blen - n, "FILEMARK");
1360                 if (descp[3] & 0x40)
1361                     n += scnpr(b + n, blen - n, "End Of Medium (EOM)");
1362                 if (descp[3] & 0x20)
1363                     n += scnpr(b + n, blen - n, "Incorrect Length Indicator "
1364                                "(ILI)");
1365                 n += scnpr(b + n, blen - n, "\n");
1366             } else {
1367                 n += scnpr(b + n, blen - n, "%s\n", dtsp);
1368                 processed = false;
1369             }
1370             break;
1371         case 5:
1372             n += scnpr(b + n, blen - n, "Block commands: ");
1373             if (add_d_len >= 2)
1374                 n += scnpr(b + n, blen - n, "Incorrect Length Indicator "
1375                            "(ILI) %s\n", (descp[3] & 0x20) ? "set" : "clear");
1376             else {
1377                 n += scnpr(b + n, blen - n, "%s\n", dtsp);
1378                 processed = false;
1379             }
1380             break;
1381         case 6:
1382             n += scnpr(b + n, blen - n, "OSD object identification\n");
1383             processed = false;
1384             break;
1385         case 7:
1386             n += scnpr(b + n, blen - n, "OSD response integrity check "
1387                              "value\n");
1388             processed = false;
1389             break;
1390         case 8:
1391             n += scnpr(b + n, blen - n, "OSD attribute identification\n");
1392             processed = false;
1393             break;
1394         case 9:         /* this is defined in SAT (SAT-2) */
1395             n += scnpr(b + n, blen - n, "ATA Status Return: ");
1396             if (add_d_len >= 12) {
1397                 int extend, count;
1398 
1399                 extend = descp[2] & 1;
1400                 count = descp[5] + (extend ? (descp[4] << 8) : 0);
1401                 n += scnpr(b + n, blen - n, "extend=%d error=0x%x \n%s"
1402                            "        count=0x%x ", extend, descp[3], lip,
1403                            count);
1404                 if (extend)
1405                     n += scnpr(b + n, blen - n,
1406                                "lba=0x%02x%02x%02x%02x%02x%02x ",
1407                                 descp[10], descp[8], descp[6], descp[11],
1408                                 descp[9], descp[7]);
1409                 else
1410                     n += scnpr(b + n, blen - n, "lba=0x%02x%02x%02x ",
1411                                descp[11], descp[9], descp[7]);
1412                 n += scnpr(b + n, blen - n, "device=0x%x status=0x%x\n",
1413                            descp[12], descp[13]);
1414             } else {
1415                 n += scnpr(b + n, blen - n, "%s\n", dtsp);
1416                 processed = false;
1417             }
1418             break;
1419         case 0xa:
1420            /* Added in SPC-4 rev 17, became 'Another ...' in rev 34 */
1421             n += scnpr(b + n, blen - n, "Another progress indication: ");
1422             if (add_d_len < 6) {
1423                 n += scnpr(b + n, blen - n, "%s\n", dtsp);
1424                 processed = false;
1425                 break;
1426             }
1427             progress = sg_get_unaligned_be16(descp + 6);
1428             pr = (progress * 100) / 65536;
1429             rem = ((progress * 100) % 65536) / 656;
1430             n += scnpr(b + n, blen - n, "%d.02%d%%\n", pr, rem);
1431             n += scnpr(b + n, blen - n, "%s        [sense_key=0x%x "
1432                        "asc,ascq=0x%x,0x%x]\n", lip, descp[2], descp[3],
1433                        descp[4]);
1434             break;
1435         case 0xb:       /* Added in SPC-4 rev 23, defined in SBC-3 rev 22 */
1436             n += scnpr(b + n, blen - n, "User data segment referral: ");
1437             if (add_d_len < 2) {
1438                 n += scnpr(b + n, blen - n, "%s\n", dtsp);
1439                 processed = false;
1440                 break;
1441             }
1442             n += scnpr(b + n, blen - n, "\n");
1443             n += uds_referral_descriptor_str(b + n, blen - n, descp,
1444                                              add_d_len, lip);
1445             break;
1446         case 0xc:       /* Added in SPC-4 rev 28 */
1447             n += scnpr(b + n, blen - n, "Forwarded sense data\n");
1448             if (add_d_len < 2) {
1449                 n += scnpr(b + n, blen - n, "%s\n", dtsp);
1450                 processed = false;
1451                 break;
1452             }
1453             n += scnpr(b + n, blen - n, "%s    FSDT: %s\n", lip,
1454                        (descp[2] & 0x80) ? "set" : "clear");
1455             j = descp[2] & 0xf;
1456             n += scnpr(b + n, blen - n, "%s    Sense data source: ", lip);
1457             switch (j) {
1458             case 0:
1459                 n += scnpr(b + n, blen - n, "%s source device\n", eccp);
1460                 break;
1461             case 1:
1462             case 2:
1463             case 3:
1464             case 4:
1465             case 5:
1466             case 6:
1467             case 7:
1468                 n += scnpr(b + n, blen - n, "%s %s %d\n", eccp, ddp, j - 1);
1469                 break;
1470             default:
1471                 n += scnpr(b + n, blen - n, "unknown [%d]\n", j);
1472             }
1473             {
1474                 char c[480];
1475 
1476                 sg_get_scsi_status_str(descp[3], sizeof(c) - 1, c);
1477                 c[sizeof(c) - 1] = '\0';
1478                 n += scnpr(b + n, blen - n, "%s    Forwarded status: %s\n",
1479                            lip, c);
1480                 if (add_d_len > 2) {
1481                     /* recursing; hope not to get carried away */
1482                     n += scnpr(b + n, blen - n, "%s vvvvvvvvvvvvvvvv\n", lip);
1483                     sg_get_sense_str(lip, descp + 4, add_d_len - 2, false,
1484                                      sizeof(c), c);
1485                     n += scnpr(b + n, blen - n, "%s", c);
1486                     n += scnpr(b + n, blen - n, "%s ^^^^^^^^^^^^^^^^\n", lip);
1487                 }
1488             }
1489             break;
1490         case 0xd:       /* Added in SBC-3 rev 36d */
1491             /* this descriptor combines descriptors 0, 1, 2 and 3 */
1492             n += scnpr(b + n, blen - n, "Direct-access block device\n");
1493             if (add_d_len < 28) {
1494                 n += scnpr(b + n, blen - n, "%s\n", dtsp);
1495                 processed = false;
1496                 break;
1497             }
1498             if (0x20 & descp[2])
1499                 n += scnpr(b + n, blen - n, "%s    ILI (incorrect length "
1500                            "indication) set\n", lip);
1501             if (0x80 & descp[4]) {
1502                 n += scnpr(b + n, blen - n, "%s    Sense key specific: ",
1503                            lip);
1504                 n += decode_sks(lip, descp, add_d_len, sense_key, &processed,
1505                                 blen - n, b + n);
1506             }
1507             n += scnpr(b + n, blen - n, "%s    Field replaceable unit code: "
1508                        "0x%x\n", lip, descp[7]);
1509             if (0x80 & descp[2]) {
1510                 n += scnpr(b + n, blen - n, "%s    Information: 0x", lip);
1511                 for (j = 0; j < 8; ++j)
1512                     n += scnpr(b + n, blen - n, "%02x", descp[8 + j]);
1513                 n += scnpr(b + n, blen - n, "\n");
1514             }
1515             n += scnpr(b + n, blen - n, "%s    Command specific: 0x", lip);
1516             for (j = 0; j < 8; ++j)
1517                 n += scnpr(b + n, blen - n, "%02x", descp[16 + j]);
1518             n += scnpr(b + n, blen - n, "\n");
1519             break;
1520         case 0xe:       /* Added in SPC-5 rev 6 (for Bind/Unbind) */
1521             n += scnpr(b + n, blen - n, "Device designation\n");
1522             j = (int)(sizeof(dd_usage_reason_str_arr) /
1523                       sizeof(dd_usage_reason_str_arr[0]));
1524             if (descp[3] < j)
1525                 n += scnpr(b + n, blen - n, "%s    Usage reason: %s\n", lip,
1526                            dd_usage_reason_str_arr[descp[3]]);
1527             else
1528                 n += scnpr(b + n, blen - n, "%s    Usage reason: "
1529                            "reserved[%d]\n", lip, descp[3]);
1530             n += sg_get_designation_descriptor_str(z, descp + 4, descp[1] - 2,
1531                                                    true, false, blen - n,
1532                                                    b + n);
1533             break;
1534         case 0xf:       /* Added in SPC-5 rev 10 (for Write buffer) */
1535             n += scnpr(b + n, blen - n, "Microcode activation ");
1536             if (add_d_len < 6) {
1537                 n += scnpr(b + n, blen - n, "%s\n", dtsp);
1538                 processed = false;
1539                 break;
1540             }
1541             progress = sg_get_unaligned_be16(descp + 6);
1542             n += scnpr(b + n, blen - n, "time: ");
1543             if (0 == progress)
1544                 n += scnpr(b + n, blen - n, "unknown\n");
1545             else
1546                 n += scnpr(b + n, blen - n, "%d seconds\n", progress);
1547             break;
1548         default:
1549             if (descp[0] >= 0x80)
1550                 n += scnpr(b + n, blen - n, "Vendor specific [0x%x]\n",
1551                            descp[0]);
1552             else
1553                 n += scnpr(b + n, blen - n, "Unknown [0x%x]\n", descp[0]);
1554             processed = false;
1555             break;
1556         }
1557         if (! processed) {
1558             if (add_d_len > 0) {
1559                 n += scnpr(b + n, blen - n, "%s    ", lip);
1560                 for (j = 0; j < add_d_len; ++j) {
1561                     if ((j > 0) && (0 == (j % 24)))
1562                         n += scnpr(b + n, blen - n, "\n%s    ", lip);
1563                     n += scnpr(b + n, blen - n, "%02x ", descp[j + 2]);
1564                 }
1565                 n += scnpr(b + n, blen - n, "\n");
1566             }
1567         }
1568         if (add_d_len < 0)
1569             n += scnpr(b + n, blen - n, "%s    short descriptor\n", lip);
1570     }
1571     return n;
1572 }
1573 
1574 /* Decode SAT ATA PASS-THROUGH fixed format sense. Shows "+" after 'count'
1575  * and/or 'lba' values to indicate that not all data in those fields is shown.
1576  * That extra field information may be available in the ATA pass-through
1577  * results log page parameter with the corresponding 'log_index'. */
1578 static int
sg_get_sense_sat_pt_fixed_str(const char * lip,const unsigned char * sp,int slen,int blen,char * b)1579 sg_get_sense_sat_pt_fixed_str(const char * lip, const unsigned char * sp,
1580                               int slen, int blen, char * b)
1581 {
1582     int n = 0;
1583     bool extend, count_upper_nz, lba_upper_nz;
1584 
1585     if ((blen < 1) || (slen < 12))
1586         return n;
1587     if (NULL == lip)
1588         lip = "";
1589     if (SPC_SK_RECOVERED_ERROR != (0xf & sp[2]))
1590         n += scnpr(b + n, blen - n, "%s  >> expected Sense key: Recovered "
1591                    "Error ??\n", lip);
1592     /* Fixed sense command-specific information field starts at sp + 8 */
1593     extend = !!(0x80 & sp[8]);
1594     count_upper_nz = !!(0x40 & sp[8]);
1595     lba_upper_nz = !!(0x20 & sp[8]);
1596     /* Fixed sense information field starts at sp + 3 */
1597     n += scnpr(b + n, blen - n, "%s  error=0x%x, status=0x%x, device=0x%x, "
1598                "count(7:0)=0x%x%c\n", lip, sp[3], sp[4], sp[5], sp[6],
1599                (count_upper_nz ? '+' : ' '));
1600     n += scnpr(b + n, blen - n, "%s  extend=%d, log_index=0x%x, "
1601                "lba_high,mid,low(7:0)=0x%x,0x%x,0x%x%c\n", lip, (int)extend,
1602                (0xf & sp[8]), sp[9], sp[10], sp[11],
1603                (lba_upper_nz ? '+' : ' '));
1604     return n;
1605 }
1606 
1607 /* Fetch sense information */
1608 int
sg_get_sense_str(const char * lip,const unsigned char * sbp,int sb_len,bool raw_sinfo,int cblen,char * cbp)1609 sg_get_sense_str(const char * lip, const unsigned char * sbp, int sb_len,
1610                  bool raw_sinfo, int cblen, char * cbp)
1611 {
1612     bool descriptor_format = false;
1613     bool sdat_ovfl = false;
1614     bool valid;
1615     int len, progress, n, r, pr, rem, blen;
1616     unsigned int info;
1617     uint8_t resp_code;
1618     const char * ebp = NULL;
1619     char ebuff[64];
1620     char b[256];
1621     struct sg_scsi_sense_hdr ssh;
1622 
1623     if ((NULL == cbp) || (cblen <= 0))
1624         return 0;
1625     else if (1 == cblen) {
1626         cbp[0] = '\0';
1627         return 0;
1628     }
1629     blen = sizeof(b);
1630     n = 0;
1631     if (NULL == lip)
1632         lip = "";
1633     if ((NULL == sbp) || (sb_len < 1)) {
1634             n += scnpr(cbp, cblen, "%s >>> sense buffer empty\n", lip);
1635             return n;
1636     }
1637     resp_code = 0x7f & sbp[0];
1638     valid = !!(sbp[0] & 0x80);
1639     len = sb_len;
1640     if (sg_scsi_normalize_sense(sbp, sb_len, &ssh)) {
1641         switch (ssh.response_code) {
1642         case 0x70:      /* fixed, current */
1643             ebp = "Fixed format, current";
1644             len = (sb_len > 7) ? (sbp[7] + 8) : sb_len;
1645             len = (len > sb_len) ? sb_len : len;
1646             sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false;
1647             break;
1648         case 0x71:      /* fixed, deferred */
1649             /* error related to a previous command */
1650             ebp = "Fixed format, <<<deferred>>>";
1651             len = (sb_len > 7) ? (sbp[7] + 8) : sb_len;
1652             len = (len > sb_len) ? sb_len : len;
1653             sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false;
1654             break;
1655         case 0x72:      /* descriptor, current */
1656             descriptor_format = true;
1657             ebp = "Descriptor format, current";
1658             sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false;
1659             break;
1660         case 0x73:      /* descriptor, deferred */
1661             descriptor_format = true;
1662             ebp = "Descriptor format, <<<deferred>>>";
1663             sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false;
1664             break;
1665         case 0x0:
1666             ebp = "Response code: 0x0 (?)";
1667             break;
1668         default:
1669             scnpr(ebuff, sizeof(ebuff), "Unknown response code: 0x%x",
1670                   ssh.response_code);
1671             ebp = ebuff;
1672             break;
1673         }
1674         n += scnpr(cbp + n, cblen - n, "%s%s; Sense key: %s\n", lip, ebp,
1675                    sg_lib_sense_key_desc[ssh.sense_key]);
1676         if (sdat_ovfl)
1677             n += scnpr(cbp + n, cblen - n, "%s<<<Sense data overflow>>>\n",
1678                        lip);
1679         if (descriptor_format) {
1680             n += scnpr(cbp + n, cblen - n, "%s%s\n", lip,
1681                        sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b));
1682             n += sg_get_sense_descriptors_str(lip, sbp, len,
1683                                               cblen - n, cbp + n);
1684         } else if ((len > 12) && (0 == ssh.asc) &&
1685                    (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) {
1686             /* SAT ATA PASS-THROUGH fixed format */
1687             n += scnpr(cbp + n, cblen - n, "%s%s\n", lip,
1688                        sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b));
1689             n += sg_get_sense_sat_pt_fixed_str(lip, sbp, len,
1690                                                cblen - n, cbp + n);
1691         } else if (len > 2) {   /* fixed format */
1692             if (len > 12)
1693                 n += scnpr(cbp + n, cblen - n, "%s%s\n", lip,
1694                            sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b));
1695             r = 0;
1696             if (strlen(lip) > 0)
1697                 r += scnpr(b + r, blen - r, "%s", lip);
1698             if (len > 6) {
1699                 info = sg_get_unaligned_be32(sbp + 3);
1700                 if (valid)
1701                     r += scnpr(b + r, blen - r, "  Info fld=0x%x [%u] ",
1702                                info, info);
1703                 else if (info > 0)
1704                     r += scnpr(b + r, blen - r, "  Valid=0, Info fld=0x%x "
1705                                "[%u] ", info, info);
1706             } else
1707                 info = 0;
1708             if (sbp[2] & 0xe0) {
1709                 if (sbp[2] & 0x80)
1710                    r += scnpr(b + r, blen - r, " FMK");
1711                             /* current command has read a filemark */
1712                 if (sbp[2] & 0x40)
1713                    r += scnpr(b + r, blen - r, " EOM");
1714                             /* end-of-medium condition exists */
1715                 if (sbp[2] & 0x20)
1716                    r += scnpr(b + r, blen - r, " ILI");
1717                             /* incorrect block length requested */
1718                 r += scnpr(b + r, blen - r, "\n");
1719             } else if (valid || (info > 0))
1720                 r += scnpr(b + r, blen - r, "\n");
1721             if ((len >= 14) && sbp[14])
1722                 r += scnpr(b + r, blen - r, "%s  Field replaceable unit "
1723                            "code: %d\n", lip, sbp[14]);
1724             if ((len >= 18) && (sbp[15] & 0x80)) {
1725                 /* sense key specific decoding */
1726                 switch (ssh.sense_key) {
1727                 case SPC_SK_ILLEGAL_REQUEST:
1728                     r += scnpr(b + r, blen - r, "%s  Sense Key Specific: "
1729                                "Error in %s: byte %d", lip,
1730                                ((sbp[15] & 0x40) ? "Command" :
1731                                                    "Data parameters"),
1732                              sg_get_unaligned_be16(sbp + 16));
1733                     if (sbp[15] & 0x08)
1734                         r += scnpr(b + r, blen - r, " bit %d\n",
1735                                    sbp[15] & 0x07);
1736                     else
1737                         r += scnpr(b + r, blen - r, "\n");
1738                     break;
1739                 case SPC_SK_NO_SENSE:
1740                 case SPC_SK_NOT_READY:
1741                     progress = sg_get_unaligned_be16(sbp + 16);
1742                     pr = (progress * 100) / 65536;
1743                     rem = ((progress * 100) % 65536) / 656;
1744                     r += scnpr(b + r, blen - r, "%s  Progress indication: "
1745                                "%d.%02d%%\n", lip, pr, rem);
1746                     break;
1747                 case SPC_SK_HARDWARE_ERROR:
1748                 case SPC_SK_MEDIUM_ERROR:
1749                 case SPC_SK_RECOVERED_ERROR:
1750                     r += scnpr(b + r, blen - r, "%s  Actual retry count: "
1751                                "0x%02x%02x\n", lip, sbp[16], sbp[17]);
1752                     break;
1753                 case SPC_SK_COPY_ABORTED:
1754                     r += scnpr(b + r, blen - r, "%s  Segment pointer: ", lip);
1755                     r += scnpr(b + r, blen - r, "Relative to start of %s, "
1756                                "byte %d", ((sbp[15] & 0x20) ?
1757                                      "segment descriptor" : "parameter list"),
1758                                sg_get_unaligned_be16(sbp + 16));
1759                     if (sbp[15] & 0x08)
1760                         r += scnpr(b + r, blen - r, " bit %d\n",
1761                                    sbp[15] & 0x07);
1762                     else
1763                         r += scnpr(b + r, blen - r, "\n");
1764                     break;
1765                 case SPC_SK_UNIT_ATTENTION:
1766                     r += scnpr(b + r, blen - r, "%s  Unit attention "
1767                                "condition queue: ", lip);
1768                     r += scnpr(b + r, blen - r, "overflow flag is %d\n",
1769                                !!(sbp[15] & 0x1));
1770                     break;
1771                 default:
1772                     r += scnpr(b + r, blen - r, "%s  Sense_key: 0x%x "
1773                                "unexpected\n", lip, ssh.sense_key);
1774                     break;
1775                 }
1776             }
1777             if (r > 0)
1778                 n += scnpr(cbp + n, cblen - n, "%s", b);
1779         } else
1780             n += scnpr(cbp + n, cblen - n, "%s fixed descriptor length "
1781                        "too short, len=%d\n", lip, len);
1782     } else {    /* unable to normalise sense buffer, something irregular */
1783         if (sb_len < 4) {       /* Too short */
1784             n += scnpr(cbp + n, cblen - n, "%ssense buffer too short (4 "
1785                        "byte minimum)\n", lip);
1786             goto check_raw;
1787         }
1788         if (0x7f == resp_code) {        /* Vendor specific */
1789             n += scnpr(cbp + n, cblen - n, "%sVendor specific sense buffer, "
1790                        "in hex:\n", lip);
1791             n += hex2str(sbp, sb_len, lip, -1, cblen - n, cbp + n);
1792             return n;   /* no need to check raw, just output in hex */
1793         }
1794         /* non-extended SCSI-1 sense data ?? */
1795         r = 0;
1796         if (strlen(lip) > 0)
1797             r += scnpr(b + r, blen - r, "%s", lip);
1798         r += scnpr(b + r, blen - r, "Probably uninitialized data.\n%s  Try "
1799                    "to view as SCSI-1 non-extended sense:\n", lip);
1800         r += scnpr(b + r, blen - r, "  AdValid=%d  Error class=%d  Error "
1801                    "code=%d\n", valid, ((sbp[0] >> 4) & 0x7),
1802                    (sbp[0] & 0xf));
1803         if (valid)
1804             scnpr(b + r, blen - r, "%s  lba=0x%x\n", lip,
1805                   sg_get_unaligned_be24(sbp + 1) & 0x1fffff);
1806         n += scnpr(cbp + n, cblen - n, "%s\n", b);
1807         len = sb_len;
1808         if (len > 32)
1809             len = 32;   /* trim in case there is a lot of rubbish */
1810     }
1811 check_raw:
1812     if (raw_sinfo) {
1813         char z[64];
1814 
1815         n += scnpr(cbp + n, cblen - n, "%s Raw sense data (in hex):\n",
1816                    lip);
1817         if (n >= (cblen - 1))
1818             return n;
1819         scnpr(z, sizeof(z), "%.50s        ", lip);
1820         n += hex2str(sbp, len, z,  -1, cblen - n, cbp + n);
1821     }
1822     return n;
1823 }
1824 
1825 /* Print sense information */
1826 void
sg_print_sense(const char * leadin,const unsigned char * sbp,int sb_len,bool raw_sinfo)1827 sg_print_sense(const char * leadin, const unsigned char * sbp, int sb_len,
1828                bool raw_sinfo)
1829 {
1830     uint32_t pg_sz = sg_get_page_size();
1831     char *cp;
1832     uint8_t *free_cp;
1833 
1834     cp = (char *)sg_memalign(pg_sz, pg_sz, &free_cp, 0);
1835     if (NULL == cp)
1836         return;
1837     sg_get_sense_str(leadin, sbp, sb_len, raw_sinfo, pg_sz, cp);
1838     pr2ws("%s", cp);
1839     free(free_cp);
1840 }
1841 
1842 /* Following examines exit_status and outputs a clear error message to
1843  * warnings_strm (usually stderr) if one is known and returns true.
1844  * Otherwise it doesn't print anything and returns false. Note that
1845  * if exit_status==0 then returns true but prints nothing and if
1846  * exit_status<0 ("some error occurred") false is returned. If leadin is
1847  * non-NULL then it is printed before the error message. */
1848 bool
sg_if_can2stderr(const char * leadin,int exit_status)1849 sg_if_can2stderr(const char * leadin, int exit_status)
1850 {
1851     const char * s = leadin ? leadin : "";
1852 
1853     if (exit_status < 0)
1854         return false;
1855     else if (0 == exit_status)
1856         return true;
1857 
1858     switch (exit_status) {
1859     case SG_LIB_CAT_NOT_READY:          /* 2 */
1860         pr2ws("%sDevice not ready\n", s);
1861         return true;
1862     case SG_LIB_CAT_MEDIUM_HARD:        /* 3 */
1863         pr2ws("%sMedium or hardware error\n", s); /* 3 sense keys: Medium, */
1864         return true;    /* hardware error or 'Blank check' for tapes */
1865     case SG_LIB_CAT_UNIT_ATTENTION:     /* 6 */
1866         pr2ws("%sDevice reported 'Unit attention'\n", s);
1867         return true;
1868     case SG_LIB_CAT_DATA_PROTECT:       /* 7 */
1869         pr2ws("%sDevice reported 'Data protect', read-only?\n", s);
1870         return true;
1871     case SG_LIB_CAT_COPY_ABORTED:       /* 10 */
1872         pr2ws("%sCopy aborted\n", s);
1873         return true;
1874     case SG_LIB_CAT_ABORTED_COMMAND:    /* 11 */
1875         pr2ws("%sCommand aborted\n", s);
1876         return true;
1877     case SG_LIB_CAT_MISCOMPARE:         /* 14 */
1878         pr2ws("%sMiscompare\n", s);
1879         return true;
1880     case SG_LIB_CAT_RES_CONFLICT:       /* 24 */
1881         pr2ws("%sReservation conflict\n", s);
1882         return true;
1883     case SG_LIB_CAT_BUSY:               /* 26 */
1884         pr2ws("%sDevice is busy, try again\n", s);
1885         return true;
1886     case SG_LIB_CAT_TASK_ABORTED:       /* 29 */
1887         pr2ws("%sTask aborted\n", s);
1888         return true;
1889     case SG_LIB_CAT_TIMEOUT:            /* 33 */
1890         pr2ws("%sTime out\n", s);
1891         return true;
1892     case SG_LIB_CAT_PROTECTION:         /* 40 */
1893         pr2ws("%sProtection error\n", s);
1894         return true;
1895     case SG_LIB_NVME_STATUS:            /* 48 */
1896         pr2ws("%sNVMe error (non-zero status)\n", s);
1897         return true;
1898     case SG_LIB_OS_BASE_ERR + EACCES:   /* 50 + */
1899         pr2ws("%sPermission denied\n", s);
1900         return true;
1901     case SG_LIB_OS_BASE_ERR + ENOMEM:
1902         pr2ws("%sUtility unable to allocate memory\n", s);
1903         return true;
1904     case SG_LIB_OS_BASE_ERR + ENOTTY:
1905         pr2ws("%sInappropriate I/O control operation\n", s);
1906         return true;
1907     case SG_LIB_OS_BASE_ERR + EPERM:
1908         pr2ws("%sNot permitted\n", s);
1909         return true;
1910     case SG_LIB_OS_BASE_ERR + EINTR:
1911         pr2ws("%sInterrupted system call\n", s);
1912         return true;
1913     case SG_LIB_OS_BASE_ERR + EIO:
1914         pr2ws("%sInput/output error\n", s);
1915         return true;
1916     case SG_LIB_OS_BASE_ERR + ENODEV:
1917         pr2ws("%sNo such device\n", s);
1918         return true;
1919     case SG_LIB_OS_BASE_ERR + ENOENT:
1920         pr2ws("%sNo such file or directory\n", s);
1921         return true;
1922     default:
1923         return false;
1924     }
1925     return false;
1926 }
1927 
1928 /* If os_err_num is within bounds then the returned value is 'os_err_num +
1929  * SG_LIB_OS_BASE_ERR' otherwise -1 is returned. If os_err_num is 0 then 0
1930  * is returned. */
1931 int
sg_convert_errno(int os_err_num)1932 sg_convert_errno(int os_err_num)
1933 {
1934     if (os_err_num <= 0) {
1935         if (os_err_num < -1)
1936             return -1;
1937         return os_err_num;
1938     }
1939     if (os_err_num < (SG_LIB_CAT_MALFORMED - SG_LIB_OS_BASE_ERR))
1940         return SG_LIB_OS_BASE_ERR + os_err_num;
1941     return -1;
1942 }
1943 
1944 /* See description in sg_lib.h header file */
1945 bool
sg_scsi_normalize_sense(const unsigned char * sbp,int sb_len,struct sg_scsi_sense_hdr * sshp)1946 sg_scsi_normalize_sense(const unsigned char * sbp, int sb_len,
1947                         struct sg_scsi_sense_hdr * sshp)
1948 {
1949     uint8_t resp_code;
1950     if (sshp)
1951         memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr));
1952     if ((NULL == sbp) || (sb_len < 1))
1953         return false;
1954     resp_code = 0x7f & sbp[0];
1955     if ((resp_code < 0x70) || (resp_code > 0x73))
1956         return false;
1957     if (sshp) {
1958         sshp->response_code = resp_code;
1959         if (sshp->response_code >= 0x72) {  /* descriptor format */
1960             if (sb_len > 1)
1961                 sshp->sense_key = (0xf & sbp[1]);
1962             if (sb_len > 2)
1963                 sshp->asc = sbp[2];
1964             if (sb_len > 3)
1965                 sshp->ascq = sbp[3];
1966             if (sb_len > 7)
1967                 sshp->additional_length = sbp[7];
1968         } else {                              /* fixed format */
1969             if (sb_len > 2)
1970                 sshp->sense_key = (0xf & sbp[2]);
1971             if (sb_len > 7) {
1972                 sb_len = (sb_len < (sbp[7] + 8)) ? sb_len : (sbp[7] + 8);
1973                 if (sb_len > 12)
1974                     sshp->asc = sbp[12];
1975                 if (sb_len > 13)
1976                     sshp->ascq = sbp[13];
1977             }
1978         }
1979     }
1980     return true;
1981 }
1982 
1983 /* Returns a SG_LIB_CAT_* value. If cannot decode sense buffer (sbp) or a
1984  * less common sense key then return SG_LIB_CAT_SENSE .*/
1985 int
sg_err_category_sense(const unsigned char * sbp,int sb_len)1986 sg_err_category_sense(const unsigned char * sbp, int sb_len)
1987 {
1988     struct sg_scsi_sense_hdr ssh;
1989 
1990     if ((sbp && (sb_len > 2)) &&
1991         (sg_scsi_normalize_sense(sbp, sb_len, &ssh))) {
1992         switch (ssh.sense_key) {        /* 0 to 0x1f */
1993         case SPC_SK_NO_SENSE:
1994             return SG_LIB_CAT_NO_SENSE;
1995         case SPC_SK_RECOVERED_ERROR:
1996             return SG_LIB_CAT_RECOVERED;
1997         case SPC_SK_NOT_READY:
1998             return SG_LIB_CAT_NOT_READY;
1999         case SPC_SK_MEDIUM_ERROR:
2000         case SPC_SK_HARDWARE_ERROR:
2001         case SPC_SK_BLANK_CHECK:
2002             return SG_LIB_CAT_MEDIUM_HARD;
2003         case SPC_SK_UNIT_ATTENTION:
2004             return SG_LIB_CAT_UNIT_ATTENTION;
2005             /* used to return SG_LIB_CAT_MEDIA_CHANGED when ssh.asc==0x28 */
2006         case SPC_SK_ILLEGAL_REQUEST:
2007             if ((0x20 == ssh.asc) && (0x0 == ssh.ascq))
2008                 return SG_LIB_CAT_INVALID_OP;
2009             else
2010                 return SG_LIB_CAT_ILLEGAL_REQ;
2011             break;
2012         case SPC_SK_ABORTED_COMMAND:
2013             if (0x10 == ssh.asc)
2014                 return SG_LIB_CAT_PROTECTION;
2015             else
2016                 return SG_LIB_CAT_ABORTED_COMMAND;
2017         case SPC_SK_MISCOMPARE:
2018             return SG_LIB_CAT_MISCOMPARE;
2019         case SPC_SK_DATA_PROTECT:
2020             return SG_LIB_CAT_DATA_PROTECT;
2021         case SPC_SK_COPY_ABORTED:
2022             return SG_LIB_CAT_COPY_ABORTED;
2023         case SPC_SK_COMPLETED:
2024         case SPC_SK_VOLUME_OVERFLOW:
2025             return SG_LIB_CAT_SENSE;
2026         default:
2027             ;   /* reserved and vendor specific sense keys fall through */
2028         }
2029     }
2030     return SG_LIB_CAT_SENSE;
2031 }
2032 
2033 /* Beware: gives wrong answer for variable length command (opcode=0x7f) */
2034 int
sg_get_command_size(unsigned char opcode)2035 sg_get_command_size(unsigned char opcode)
2036 {
2037     switch ((opcode >> 5) & 0x7) {
2038     case 0:
2039         return 6;
2040     case 1: case 2: case 6: case 7:
2041         return 10;
2042     case 3: case 5:
2043         return 12;
2044         break;
2045     case 4:
2046         return 16;
2047     default:
2048         return 10;
2049     }
2050 }
2051 
2052 void
sg_get_command_name(const unsigned char * cmdp,int peri_type,int buff_len,char * buff)2053 sg_get_command_name(const unsigned char * cmdp, int peri_type, int buff_len,
2054                     char * buff)
2055 {
2056     int service_action;
2057 
2058     if ((NULL == buff) || (buff_len < 1))
2059         return;
2060     else if (1 == buff_len) {
2061         buff[0] = '\0';
2062         return;
2063     }
2064     if (NULL == cmdp) {
2065         scnpr(buff, buff_len, "%s", "<null> command pointer");
2066         return;
2067     }
2068     service_action = (SG_VARIABLE_LENGTH_CMD == cmdp[0]) ?
2069                      sg_get_unaligned_be16(cmdp + 8) : (cmdp[1] & 0x1f);
2070     sg_get_opcode_sa_name(cmdp[0], service_action, peri_type, buff_len, buff);
2071 }
2072 
2073 struct op_code2sa_t {
2074     int op_code;
2075     int pdt_match;      /* -1->all; 0->disk,ZBC,RCB, 1->tape+adc+smc */
2076     struct sg_lib_value_name_t * arr;
2077     const char * prefix;
2078 };
2079 
2080 static struct op_code2sa_t op_code2sa_arr[] = {
2081     {SG_VARIABLE_LENGTH_CMD, -1, sg_lib_variable_length_arr, NULL},
2082     {SG_MAINTENANCE_IN, -1, sg_lib_maint_in_arr, NULL},
2083     {SG_MAINTENANCE_OUT, -1, sg_lib_maint_out_arr, NULL},
2084     {SG_SERVICE_ACTION_IN_12, -1, sg_lib_serv_in12_arr, NULL},
2085     {SG_SERVICE_ACTION_OUT_12, -1, sg_lib_serv_out12_arr, NULL},
2086     {SG_SERVICE_ACTION_IN_16, -1, sg_lib_serv_in16_arr, NULL},
2087     {SG_SERVICE_ACTION_OUT_16, -1, sg_lib_serv_out16_arr, NULL},
2088     {SG_SERVICE_ACTION_BIDI, -1, sg_lib_serv_bidi_arr, NULL},
2089     {SG_PERSISTENT_RESERVE_IN, -1, sg_lib_pr_in_arr, "Persistent reserve in"},
2090     {SG_PERSISTENT_RESERVE_OUT, -1, sg_lib_pr_out_arr,
2091      "Persistent reserve out"},
2092     {SG_3PARTY_COPY_OUT, -1, sg_lib_xcopy_sa_arr, NULL},
2093     {SG_3PARTY_COPY_IN, -1, sg_lib_rec_copy_sa_arr, NULL},
2094     {SG_READ_BUFFER, -1, sg_lib_read_buff_arr, "Read buffer(10)"},
2095     {SG_READ_BUFFER_16, -1, sg_lib_read_buff_arr, "Read buffer(16)"},
2096     {SG_READ_ATTRIBUTE, -1, sg_lib_read_attr_arr, "Read attribute"},
2097     {SG_READ_POSITION, 1, sg_lib_read_pos_arr, "Read position"},
2098     {SG_SANITIZE, 0, sg_lib_sanitize_sa_arr, "Sanitize"},
2099     {SG_WRITE_BUFFER, -1, sg_lib_write_buff_arr, "Write buffer"},
2100     {SG_ZONING_IN, 0, sg_lib_zoning_in_arr, NULL},
2101     {SG_ZONING_OUT, 0, sg_lib_zoning_out_arr, NULL},
2102     {0xffff, -1, NULL, NULL},
2103 };
2104 
2105 void
sg_get_opcode_sa_name(unsigned char cmd_byte0,int service_action,int peri_type,int buff_len,char * buff)2106 sg_get_opcode_sa_name(unsigned char cmd_byte0, int service_action,
2107                       int peri_type, int buff_len, char * buff)
2108 {
2109     int d_pdt;
2110     const struct sg_lib_value_name_t * vnp;
2111     const struct op_code2sa_t * osp;
2112     char b[80];
2113 
2114     if ((NULL == buff) || (buff_len < 1))
2115         return;
2116     else if (1 == buff_len) {
2117         buff[0] = '\0';
2118         return;
2119     }
2120 
2121     if (peri_type < 0)
2122         peri_type = 0;
2123     d_pdt = sg_lib_pdt_decay(peri_type);
2124     for (osp = op_code2sa_arr; osp->arr; ++osp) {
2125         if ((int)cmd_byte0 == osp->op_code) {
2126             if ((osp->pdt_match < 0) || (d_pdt == osp->pdt_match)) {
2127                 vnp = get_value_name(osp->arr, service_action, peri_type);
2128                 if (vnp) {
2129                     if (osp->prefix)
2130                         scnpr(buff, buff_len, "%s, %s", osp->prefix,
2131                               vnp->name);
2132                     else
2133                         scnpr(buff, buff_len, "%s", vnp->name);
2134                 } else {
2135                     sg_get_opcode_name(cmd_byte0, peri_type, sizeof(b), b);
2136                     scnpr(buff, buff_len, "%s service action=0x%x", b,
2137                           service_action);
2138                 }
2139             } else
2140                 sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff);
2141             return;
2142         }
2143     }
2144     sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff);
2145 }
2146 
2147 void
sg_get_opcode_name(unsigned char cmd_byte0,int peri_type,int buff_len,char * buff)2148 sg_get_opcode_name(unsigned char cmd_byte0, int peri_type, int buff_len,
2149                    char * buff)
2150 {
2151     const struct sg_lib_value_name_t * vnp;
2152     int grp;
2153 
2154     if ((NULL == buff) || (buff_len < 1))
2155         return;
2156     else if (1 == buff_len) {
2157         buff[0] = '\0';
2158         return;
2159     }
2160     if (SG_VARIABLE_LENGTH_CMD == cmd_byte0) {
2161         scnpr(buff, buff_len, "%s", "Variable length");
2162         return;
2163     }
2164     grp = (cmd_byte0 >> 5) & 0x7;
2165     switch (grp) {
2166     case 0:
2167     case 1:
2168     case 2:
2169     case 4:
2170     case 5:
2171         vnp = get_value_name(sg_lib_normal_opcodes, cmd_byte0, peri_type);
2172         if (vnp)
2173             scnpr(buff, buff_len, "%s", vnp->name);
2174         else
2175             scnpr(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0);
2176         break;
2177     case 3:
2178         scnpr(buff, buff_len, "Reserved [0x%x]", (int)cmd_byte0);
2179         break;
2180     case 6:
2181     case 7:
2182         scnpr(buff, buff_len, "Vendor specific [0x%x]", (int)cmd_byte0);
2183         break;
2184     default:
2185         scnpr(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0);
2186         break;
2187     }
2188 }
2189 
2190 /* Iterates to next designation descriptor in the device identification
2191  * VPD page. The 'initial_desig_desc' should point to start of first
2192  * descriptor with 'page_len' being the number of valid bytes in that
2193  * and following descriptors. To start, 'off' should point to a negative
2194  * value, thereafter it should point to the value yielded by the previous
2195  * call. If 0 returned then 'initial_desig_desc + *off' should be a valid
2196  * descriptor; returns -1 if normal end condition and -2 for an abnormal
2197  * termination. Matches association, designator_type and/or code_set when
2198  * any of those values are greater than or equal to zero. */
2199 int
sg_vpd_dev_id_iter(const unsigned char * initial_desig_desc,int page_len,int * off,int m_assoc,int m_desig_type,int m_code_set)2200 sg_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len,
2201                    int * off, int m_assoc, int m_desig_type, int m_code_set)
2202 {
2203     bool fltr = ((m_assoc >= 0) || (m_desig_type >= 0) || (m_code_set >= 0));
2204     int k = *off;
2205     const unsigned char * bp = initial_desig_desc;
2206 
2207     while ((k + 3) < page_len) {
2208         k = (k < 0) ? 0 : (k + bp[k + 3] + 4);
2209         if ((k + 4) > page_len)
2210             break;
2211         if (fltr) {
2212             if (m_code_set >= 0) {
2213                 if ((bp[k] & 0xf) != m_code_set)
2214                     continue;
2215             }
2216             if (m_assoc >= 0) {
2217                 if (((bp[k + 1] >> 4) & 0x3) != m_assoc)
2218                     continue;
2219             }
2220             if (m_desig_type >= 0) {
2221                 if ((bp[k + 1] & 0xf) != m_desig_type)
2222                     continue;
2223             }
2224         }
2225         *off = k;
2226         return 0;
2227     }
2228     return (k == page_len) ? -1 : -2;
2229 }
2230 
2231 static const char * const bad_sense_cat = "Bad sense category";
2232 
2233 /* Yield string associated with sense category. Returns 'buff' (or pointer
2234  * to "Bad sense category" if 'buff' is NULL). If sense_cat unknown then
2235  * yield "Sense category: <sense_cat>" string. */
2236 const char *
sg_get_category_sense_str(int sense_cat,int buff_len,char * buff,int verbose)2237 sg_get_category_sense_str(int sense_cat, int buff_len, char * buff,
2238                           int verbose)
2239 {
2240     int n;
2241 
2242     if (NULL == buff)
2243         return bad_sense_cat;
2244     if (buff_len <= 0)
2245         return buff;
2246     switch (sense_cat) {
2247     case SG_LIB_CAT_CLEAN:              /* 0 */
2248         scnpr(buff, buff_len, "No errors");
2249         break;
2250     case SG_LIB_SYNTAX_ERROR:           /* 1 */
2251         scnpr(buff, buff_len, "Syntax error");
2252         break;
2253     case SG_LIB_CAT_NOT_READY:          /* 2 */
2254         n = scnpr(buff, buff_len, "Not ready");
2255         if (verbose && (n < (buff_len - 1)))
2256             scnpr(buff + n, buff_len - n, " sense key");
2257         break;
2258     case SG_LIB_CAT_MEDIUM_HARD:        /* 3 */
2259         n = scnpr(buff, buff_len, "Medium or hardware error");
2260         if (verbose && (n < (buff_len - 1)))
2261             scnpr(buff + n, buff_len - n, " sense key (plus blank check)");
2262         break;
2263     case SG_LIB_CAT_ILLEGAL_REQ:        /* 5 */
2264         n = scnpr(buff, buff_len, "Illegal request");
2265         if (verbose && (n < (buff_len - 1)))
2266             scnpr(buff + n, buff_len - n, " sense key, apart from Invalid "
2267                   "opcode");
2268         break;
2269     case SG_LIB_CAT_UNIT_ATTENTION:     /* 6 */
2270         n = scnpr(buff, buff_len, "Unit attention");
2271         if (verbose && (n < (buff_len - 1)))
2272             scnpr(buff + n, buff_len - n, " sense key");
2273         break;
2274     case SG_LIB_CAT_DATA_PROTECT:       /* 7 */
2275         n = scnpr(buff, buff_len, "Data protect");
2276         if (verbose && (n < (buff_len - 1)))
2277             scnpr(buff + n, buff_len - n, " sense key, write protected "
2278                      "media?");
2279         break;
2280     case SG_LIB_CAT_INVALID_OP:         /* 9 */
2281         n = scnpr(buff, buff_len, "Illegal request, invalid opcode");
2282         if (verbose && (n < (buff_len - 1)))
2283             scnpr(buff + n, buff_len - n, " sense key");
2284         break;
2285     case SG_LIB_CAT_COPY_ABORTED:       /* 10 */
2286         n = scnpr(buff, buff_len, "Copy aborted");
2287         if (verbose && (n < (buff_len - 1)))
2288             scnpr(buff + n, buff_len - n, " sense key");
2289         break;
2290     case SG_LIB_CAT_ABORTED_COMMAND:    /* 11 */
2291         n = scnpr(buff, buff_len, "Aborted command");
2292         if (verbose && (n < (buff_len - 1)))
2293             scnpr(buff + n, buff_len - n, " sense key, other than "
2294                      "protection related (asc=0x10)");
2295         break;
2296     case SG_LIB_CAT_MISCOMPARE:         /* 14 */
2297         n = scnpr(buff, buff_len, "Miscompare");
2298         if (verbose && (n < (buff_len - 1)))
2299             scnpr(buff + n, buff_len - n, " sense key");
2300         break;
2301     case SG_LIB_FILE_ERROR:             /* 15 */
2302         scnpr(buff, buff_len, "File error");
2303         break;
2304     case SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO:  /* 17 */
2305         scnpr(buff, buff_len, "Illegal request with info");
2306         break;
2307     case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO:  /* 18 */
2308         scnpr(buff, buff_len, "Medium or hardware error with info");
2309         break;
2310     case SG_LIB_CAT_NO_SENSE:           /* 20 */
2311         n = scnpr(buff, buff_len, "No sense key");
2312         if (verbose && (n < (buff_len - 1)))
2313             scnpr(buff + n, buff_len - n, " probably additional sense "
2314                      "information");
2315         break;
2316     case SG_LIB_CAT_RECOVERED:          /* 21 */
2317         n = scnpr(buff, buff_len, "Recovered error");
2318         if (verbose && (n < (buff_len - 1)))
2319             scnpr(buff + n, buff_len - n, " sense key");
2320         break;
2321     case SG_LIB_CAT_RES_CONFLICT:       /* 24 */
2322         n = scnpr(buff, buff_len, "Reservation conflict");
2323         if (verbose && (n < (buff_len - 1)))
2324             scnpr(buff + n, buff_len - n, " SCSI status");
2325         break;
2326     case SG_LIB_CAT_CONDITION_MET:      /* 25 */
2327         n = scnpr(buff, buff_len, "Condition met");
2328         if (verbose && (n < (buff_len - 1)))
2329             scnpr(buff + n, buff_len - n, " SCSI status");
2330         break;
2331     case SG_LIB_CAT_BUSY:               /* 26 */
2332         n = scnpr(buff, buff_len, "Busy");
2333         if (verbose && (n < (buff_len - 1)))
2334             scnpr(buff + n, buff_len - n, " SCSI status");
2335         break;
2336     case SG_LIB_CAT_TS_FULL:            /* 27 */
2337         n = scnpr(buff, buff_len, "Task set full");
2338         if (verbose && (n < (buff_len - 1)))
2339             scnpr(buff + n, buff_len - n, " SCSI status");
2340         break;
2341     case SG_LIB_CAT_ACA_ACTIVE:         /* 28 */
2342         n = scnpr(buff, buff_len, "ACA active");
2343         if (verbose && (n < (buff_len - 1)))
2344             scnpr(buff + n, buff_len - n, " SCSI status");
2345         break;
2346     case SG_LIB_CAT_TASK_ABORTED:       /* 29 */
2347         n = scnpr(buff, buff_len, "Task aborted");
2348         if (verbose && (n < (buff_len - 1)))
2349             scnpr(buff + n, buff_len - n, " SCSI status");
2350         break;
2351     case SG_LIB_CAT_TIMEOUT:            /* 33 */
2352         scnpr(buff, buff_len, "SCSI command timeout");
2353         break;
2354     case SG_LIB_CAT_PROTECTION:         /* 40 */
2355         n = scnpr(buff, buff_len, "Aborted command, protection");
2356         if (verbose && (n < (buff_len - 1)))
2357             scnpr(buff + n, buff_len - n, " information (PI) problem");
2358         break;
2359     case SG_LIB_CAT_PROTECTION_WITH_INFO: /* 41 */
2360         n = scnpr(buff, buff_len, "Aborted command with info, protection");
2361         if (verbose && (n < (buff_len - 1)))
2362             scnpr(buff + n, buff_len - n, " information (PI) problem");
2363         break;
2364     case SG_LIB_CAT_MALFORMED:          /* 97 */
2365         n = scnpr(buff, buff_len, "Malformed response");
2366         if (verbose && (n < (buff_len - 1)))
2367             scnpr(buff + n, buff_len - n, " to SCSI command");
2368         break;
2369     case SG_LIB_CAT_SENSE:              /* 98 */
2370         n = scnpr(buff, buff_len, "Some other sense data problem");
2371         if (verbose && (n < (buff_len - 1)))
2372             scnpr(buff + n, buff_len - n, ", try '-v' option for more "
2373                      "information");
2374         break;
2375     case SG_LIB_CAT_OTHER:              /* 99 */
2376         n = scnpr(buff, buff_len, "Some other error/warning has occurred");
2377         if ((0 == verbose) && (n < (buff_len - 1)))
2378             scnpr(buff + n, buff_len - n, ", possible transport of driver "
2379                      "issue");
2380         break;
2381     default:
2382         if ((sense_cat > SG_LIB_OS_BASE_ERR) &&
2383             (sense_cat < (SG_LIB_OS_BASE_ERR + 47))) {
2384             int k = sense_cat - SG_LIB_OS_BASE_ERR;
2385 
2386             n = scnpr(buff, buff_len, "OS error: %s [%d]", safe_strerror(k),
2387                       k);
2388         } else {
2389             n = scnpr(buff, buff_len, "Sense category: %d", sense_cat);
2390             if ((0 == verbose) && (n < (buff_len - 1)))
2391                 scnpr(buff + n, buff_len - n, ", try '-v' option for more "
2392                       "information");
2393         }
2394         break;
2395     }
2396     return buff;
2397 }
2398 
2399 static const char * sg_sfs_spc_reserved = "SPC Reserved";
2400 static const char * sg_sfs_sbc_reserved = "SBC Reserved";
2401 static const char * sg_sfs_ssc_reserved = "SSC Reserved";
2402 static const char * sg_sfs_zbc_reserved = "ZBC Reserved";
2403 static const char * sg_sfs_reserved = "Reserved";
2404 
2405 /* Yield SCSI Feature Set (sfs) string. When 'peri_type' is < -1 (or > 31)
2406  * returns pointer to string (same as 'buff') associated with 'sfs_code'.
2407  * When 'peri_type' is between -1 (for SPC) and 31 (inclusive) then a match
2408  * on both 'sfs_code' and 'peri_type' is required. If 'foundp' is not NULL
2409  * then where it points is set to true if a match is found else it is set to
2410  * false. If 'buff' is not NULL then in the case of a match a descriptive
2411  * string is written to 'buff' while if there is not a not then a string
2412  * ending in "Reserved" is written (and may be prefixed with SPC, SBC, SSC
2413  * or ZBC). Returns 'buff' (i.e. a pointer value) even if it is NULL.
2414  * Example:
2415  *    char b[64];
2416  *    ...
2417  *    printf("%s\n", sg_get_sfs_str(sfs_code, -2, sizeof(b), b, NULL, 0));
2418  */
2419 const char *
sg_get_sfs_str(uint16_t sfs_code,int peri_type,int buff_len,char * buff,bool * foundp,int verbose)2420 sg_get_sfs_str(uint16_t sfs_code, int peri_type, int buff_len, char * buff,
2421                bool * foundp, int verbose)
2422 {
2423     const struct sg_lib_value_name_t * vnp = NULL;
2424     int n = 0;
2425     int my_pdt;
2426 
2427     if ((NULL == buff) || (buff_len < 1)) {
2428         if (foundp)
2429             *foundp = false;
2430         return NULL;
2431     } else if (1 == buff_len) {
2432         buff[0] = '\0';
2433         if (foundp)
2434             *foundp = false;
2435         return NULL;
2436     }
2437     my_pdt = ((peri_type < -1) || (peri_type > 0x1f)) ? -2 : peri_type;
2438     vnp = get_value_name(sg_lib_scsi_feature_sets, sfs_code, my_pdt);
2439     if (vnp && (-2 != my_pdt)) {
2440         if (peri_type != vnp->peri_dev_type)
2441             vnp = NULL;         /* shouldn't really happen */
2442     }
2443     if (foundp)
2444         *foundp = vnp ? true : false;
2445     if (sfs_code < 0x100) {             /* SPC Feature Sets */
2446         if (vnp) {
2447             if (verbose)
2448                 n += scnpr(buff, buff_len, "SPC %s", vnp->name);
2449             else
2450                 n += scnpr(buff, buff_len, "%s", vnp->name);
2451         } else
2452             n += scnpr(buff, buff_len, "%s", sg_sfs_spc_reserved);
2453     } else if (sfs_code < 0x200) {      /* SBC Feature Sets */
2454         if (vnp) {
2455             if (verbose)
2456                 n += scnpr(buff, buff_len, "SBC %s", vnp->name);
2457             else
2458                 n += scnpr(buff, buff_len, "%s", vnp->name);
2459         } else
2460             n += scnpr(buff, buff_len, "%s", sg_sfs_sbc_reserved);
2461     } else if (sfs_code < 0x300) {      /* SSC Feature Sets */
2462         if (vnp) {
2463             if (verbose)
2464                 n += scnpr(buff, buff_len, "SSC %s", vnp->name);
2465             else
2466                 n += scnpr(buff, buff_len, "%s", vnp->name);
2467         } else
2468             n += scnpr(buff, buff_len, "%s", sg_sfs_ssc_reserved);
2469     } else if (sfs_code < 0x400) {      /* ZBC Feature Sets */
2470         if (vnp) {
2471             if (verbose)
2472                 n += scnpr(buff, buff_len, "ZBC %s", vnp->name);
2473             else
2474                 n += scnpr(buff, buff_len, "%s", vnp->name);
2475         } else
2476             n += scnpr(buff, buff_len, "%s", sg_sfs_zbc_reserved);
2477     } else {                            /* Other SCSI Feature Sets */
2478         if (vnp) {
2479             if (verbose)
2480                 n += scnpr(buff, buff_len, "[unrecognized PDT] %s",
2481                            vnp->name);
2482             else
2483                 n += scnpr(buff, buff_len, "%s", vnp->name);
2484         } else
2485             n += scnpr(buff, buff_len, "%s", sg_sfs_reserved);
2486 
2487     }
2488     if (verbose > 4)
2489         pr2serr("%s: length of returned string (n) %d\n", __func__, n);
2490     return buff;
2491 }
2492 
2493 /* This is a heuristic that takes into account the command bytes and length
2494  * to decide whether the presented unstructured sequence of bytes could be
2495  * a SCSI command. If so it returns true otherwise false. Vendor specific
2496  * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed
2497  * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The
2498  * only SCSI commands considered above 16 bytes of length are the Variable
2499  * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e).
2500  * Both have an inbuilt length field which can be cross checked with clen.
2501  * No NVMe commands (64 bytes long plus some extra added by some OSes) have
2502  * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS
2503  * structures that are sent across the wire. The FIS register structure is
2504  * used to move a command from a SATA host to device, but the ATA 'command'
2505  * is not the first byte. So it is harder to say what will happen if a
2506  * FIS structure is presented as a SCSI command, hopfully there is a low
2507  * probability this function will yield true in that case. */
2508 bool
sg_is_scsi_cdb(const uint8_t * cdbp,int clen)2509 sg_is_scsi_cdb(const uint8_t * cdbp, int clen)
2510 {
2511     int ilen, sa;
2512     uint8_t opcode;
2513     uint8_t top3bits;
2514 
2515     if (clen < 6)
2516         return false;
2517     opcode = cdbp[0];
2518     top3bits = opcode >> 5;
2519     if (0x3 == top3bits) {
2520         if ((clen < 12) || (clen % 4))
2521             return false;       /* must be modulo 4 and 12 or more bytes */
2522         switch (opcode) {
2523         case 0x7e:      /* Extended cdb (XCDB) */
2524             ilen = 4 + sg_get_unaligned_be16(cdbp + 2);
2525             return (ilen == clen);
2526         case 0x7f:      /* Variable Length cdb */
2527             ilen = 8 + cdbp[7];
2528             sa = sg_get_unaligned_be16(cdbp + 8);
2529             /* service action (sa) 0x0 is reserved */
2530             return ((ilen == clen) && sa);
2531         default:
2532             return false;
2533         }
2534     } else if (clen <= 16) {
2535         switch (clen) {
2536         case 6:
2537             if (top3bits > 0x5)         /* vendor */
2538                 return true;
2539             return (0x0 == top3bits);   /* 6 byte cdb */
2540         case 10:
2541             if (top3bits > 0x5)         /* vendor */
2542                 return true;
2543             return ((0x1 == top3bits) || (0x2 == top3bits)); /* 10 byte cdb */
2544         case 16:
2545             if (top3bits > 0x5)         /* vendor */
2546                 return true;
2547             return (0x4 == top3bits);   /* 16 byte cdb */
2548         case 12:
2549             if (top3bits > 0x5)         /* vendor */
2550                 return true;
2551             return (0x5 == top3bits);   /* 12 byte cdb */
2552         default:
2553             return false;
2554         }
2555     }
2556     /* NVMe probably falls out here, clen > 16 and (opcode < 0x60 or
2557      * opcode > 0x7f). */
2558     return false;
2559 }
2560 
2561 /* Yield string associated with NVMe command status value in sct_sc. It
2562  * expects to decode DW3 bits 27:17 from the completion queue. Bits 27:25
2563  * are the Status Code Type (SCT) and bits 24:17 are the Status Code (SC).
2564  * Bit 17 in DW3 should be bit 0 in sct_sc. If no status string is found
2565  * a string of the form "Reserved [0x<sct_sc_in_hex>]" is generated.
2566  * Returns 'buff'. Does nothing if buff_len<=0 or if buff is NULL.*/
2567 char *
sg_get_nvme_cmd_status_str(uint16_t sct_sc,int b_len,char * b)2568 sg_get_nvme_cmd_status_str(uint16_t sct_sc, int b_len, char * b)
2569 {
2570     int k;
2571     uint16_t s = 0x3ff & sct_sc;
2572     const struct sg_lib_value_name_t * vp = sg_lib_nvme_cmd_status_arr;
2573 
2574     if ((b_len <= 0) || (NULL == b))
2575         return b;
2576     else if (1 == b_len) {
2577         b[0] = '\0';
2578         return b;
2579     }
2580     for (k = 0; (vp->name && (k < 1000)); ++k, ++vp) {
2581         if (s == (uint16_t)vp->value) {
2582             strncpy(b, vp->name, b_len);
2583             b[b_len - 1] = '\0';
2584             return b;
2585         }
2586     }
2587     if (k >= 1000)
2588         pr2ws("%s: where is sentinel for sg_lib_nvme_cmd_status_arr ??\n",
2589                         __func__);
2590     snprintf(b, b_len, "Reserved [0x%x]", sct_sc);
2591     return b;
2592 }
2593 
2594 /* Attempts to map NVMe status value ((SCT << 8) | SC) to SCSI status,
2595  * sense_key, asc and ascq tuple. If successful returns true and writes to
2596  * non-NULL pointer arguments; otherwise returns false. */
2597 bool
sg_nvme_status2scsi(uint16_t sct_sc,uint8_t * status_p,uint8_t * sk_p,uint8_t * asc_p,uint8_t * ascq_p)2598 sg_nvme_status2scsi(uint16_t sct_sc, uint8_t * status_p, uint8_t * sk_p,
2599                     uint8_t * asc_p, uint8_t * ascq_p)
2600 {
2601     int k, ind;
2602     uint16_t s = 0x3ff & sct_sc;
2603     struct sg_lib_value_name_t * vp = sg_lib_nvme_cmd_status_arr;
2604     struct sg_lib_4tuple_u8 * mp = sg_lib_scsi_status_sense_arr;
2605 
2606     for (k = 0; (vp->name && (k < 1000)); ++k, ++vp) {
2607         if (s == (uint16_t)vp->value)
2608             break;
2609     }
2610     if (k >= 1000) {
2611         pr2ws("%s: where is sentinel for sg_lib_nvme_cmd_status_arr ??\n",
2612               __func__);
2613         return false;
2614     }
2615     if (NULL == vp->name)
2616         return false;
2617     ind = vp->peri_dev_type;
2618 
2619 
2620     for (k = 0; (0xff != mp->t2) && k < 1000; ++k, ++mp)
2621         ;       /* count entries for valid index range */
2622     if (k >= 1000) {
2623         pr2ws("%s: where is sentinel for sg_lib_scsi_status_sense_arr ??\n",
2624               __func__);
2625         return false;
2626     } else if (ind >= k)
2627         return false;
2628     mp = sg_lib_scsi_status_sense_arr + ind;
2629     if (status_p)
2630         *status_p = mp->t1;
2631     if (sk_p)
2632         *sk_p = mp->t2;
2633     if (asc_p)
2634         *asc_p = mp->t3;
2635     if (ascq_p)
2636         *ascq_p = mp->t4;
2637     return true;
2638 }
2639 
2640 /* safe_strerror() contributed by Clayton Weaver <cgweav at email dot com>
2641  * Allows for situation in which strerror() is given a wild value (or the
2642  * C library is incomplete) and returns NULL. Still not thread safe.
2643  */
2644 
2645 static char safe_errbuf[64] = {'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ',
2646                                'e', 'r', 'r', 'n', 'o', ':', ' ', 0};
2647 
2648 char *
safe_strerror(int errnum)2649 safe_strerror(int errnum)
2650 {
2651     size_t len;
2652     char * errstr;
2653 
2654     if (errnum < 0)
2655         errnum = -errnum;
2656     errstr = strerror(errnum);
2657     if (NULL == errstr) {
2658         len = strlen(safe_errbuf);
2659         scnpr(safe_errbuf + len, sizeof(safe_errbuf) - len, "%i", errnum);
2660         return safe_errbuf;
2661     }
2662     return errstr;
2663 }
2664 
2665 static void
trimTrailingSpaces(char * b)2666 trimTrailingSpaces(char * b)
2667 {
2668     int k;
2669 
2670     for (k = ((int)strlen(b) - 1); k >= 0; --k) {
2671         if (' ' != b[k])
2672             break;
2673     }
2674     if ('\0' != b[k + 1])
2675         b[k + 1] = '\0';
2676 }
2677 
2678 /* Note the ASCII-hex output goes to stdout. [Most other output from functions
2679  * in this file go to sg_warnings_strm (default stderr).]
2680  * 'no_ascii' allows for 3 output types:
2681  *     > 0     each line has address then up to 16 ASCII-hex bytes
2682  *     = 0     in addition, the bytes are listed in ASCII to the right
2683  *     < 0     only the ASCII-hex bytes are listed (i.e. without address) */
2684 static void
dStrHexFp(const char * str,int len,int no_ascii,FILE * fp)2685 dStrHexFp(const char* str, int len, int no_ascii, FILE * fp)
2686 {
2687     const char * p = str;
2688     const char * formatstr;
2689     unsigned char c;
2690     char buff[82];
2691     int a = 0;
2692     int bpstart = 5;
2693     const int cpstart = 60;
2694     int cpos = cpstart;
2695     int bpos = bpstart;
2696     int i, k, blen;
2697 
2698     if (len <= 0)
2699         return;
2700     blen = (int)sizeof(buff);
2701     if (0 == no_ascii)  /* address at left and ASCII at right */
2702         formatstr = "%.76s\n";
2703     else                        /* previously when > 0 str was "%.58s\n" */
2704         formatstr = "%s\n";     /* when < 0 str was: "%.48s\n" */
2705     memset(buff, ' ', 80);
2706     buff[80] = '\0';
2707     if (no_ascii < 0) {
2708         bpstart = 0;
2709         bpos = bpstart;
2710         for (k = 0; k < len; k++) {
2711             c = *p++;
2712             if (bpos == (bpstart + (8 * 3)))
2713                 bpos++;
2714             scnpr(&buff[bpos], blen - bpos, "%.2x", (int)(unsigned char)c);
2715             buff[bpos + 2] = ' ';
2716             if ((k > 0) && (0 == ((k + 1) % 16))) {
2717                 trimTrailingSpaces(buff);
2718                 fprintf(fp, formatstr, buff);
2719                 bpos = bpstart;
2720                 memset(buff, ' ', 80);
2721             } else
2722                 bpos += 3;
2723         }
2724         if (bpos > bpstart) {
2725             buff[bpos + 2] = '\0';
2726             trimTrailingSpaces(buff);
2727             fprintf(fp, "%s\n", buff);
2728         }
2729         return;
2730     }
2731     /* no_ascii>=0, start each line with address (offset) */
2732     k = scnpr(buff + 1, blen - 1, "%.2x", a);
2733     buff[k + 1] = ' ';
2734 
2735     for (i = 0; i < len; i++) {
2736         c = *p++;
2737         bpos += 3;
2738         if (bpos == (bpstart + (9 * 3)))
2739             bpos++;
2740         scnpr(&buff[bpos], blen - bpos, "%.2x", (int)(unsigned char)c);
2741         buff[bpos + 2] = ' ';
2742         if (no_ascii)
2743             buff[cpos++] = ' ';
2744         else {
2745             if (! my_isprint(c))
2746                 c = '.';
2747             buff[cpos++] = c;
2748         }
2749         if (cpos > (cpstart + 15)) {
2750             if (no_ascii)
2751                 trimTrailingSpaces(buff);
2752             fprintf(fp, formatstr, buff);
2753             bpos = bpstart;
2754             cpos = cpstart;
2755             a += 16;
2756             memset(buff, ' ', 80);
2757             k = scnpr(buff + 1, blen - 1, "%.2x", a);
2758             buff[k + 1] = ' ';
2759         }
2760     }
2761     if (cpos > cpstart) {
2762         buff[cpos] = '\0';
2763         if (no_ascii)
2764             trimTrailingSpaces(buff);
2765         fprintf(fp, "%s\n", buff);
2766     }
2767 }
2768 
2769 void
dStrHex(const char * str,int len,int no_ascii)2770 dStrHex(const char* str, int len, int no_ascii)
2771 {
2772     dStrHexFp(str, len, no_ascii, stdout);
2773 }
2774 
2775 void
dStrHexErr(const char * str,int len,int no_ascii)2776 dStrHexErr(const char* str, int len, int no_ascii)
2777 {
2778     dStrHexFp(str, len, no_ascii,
2779               (sg_warnings_strm ? sg_warnings_strm : stderr));
2780 }
2781 
2782 #define DSHS_LINE_BLEN 160
2783 #define DSHS_BPL 16
2784 
2785 /* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space
2786  * separated) to 'b' not to exceed 'b_len' characters. Each line
2787  * starts with 'leadin' (NULL for no leadin) and there are 16 bytes
2788  * per line with an extra space between the 8th and 9th bytes. 'format'
2789  * is 0 for repeat in printable ASCII ('.' for non printable) to
2790  * right of each line; 1 don't (so just output ASCII hex). Returns
2791  * number of bytes written to 'b' excluding the trailing '\0'. */
2792 int
dStrHexStr(const char * str,int len,const char * leadin,int format,int b_len,char * b)2793 dStrHexStr(const char * str, int len, const char * leadin, int format,
2794            int b_len, char * b)
2795 {
2796     unsigned char c;
2797     int bpstart, bpos, k, n, prior_ascii_len;
2798     bool want_ascii;
2799     char buff[DSHS_LINE_BLEN + 2];
2800     char a[DSHS_BPL + 1];
2801     const char * p = str;
2802 
2803     if (len <= 0) {
2804         if (b_len > 0)
2805             b[0] = '\0';
2806         return 0;
2807     }
2808     if (b_len <= 0)
2809         return 0;
2810     want_ascii = !format;
2811     if (want_ascii) {
2812         memset(a, ' ', DSHS_BPL);
2813         a[DSHS_BPL] = '\0';
2814     }
2815     if (leadin) {
2816         bpstart = strlen(leadin);
2817         /* Cap leadin at (DSHS_LINE_BLEN - 70) characters */
2818         if (bpstart > (DSHS_LINE_BLEN - 70))
2819             bpstart = DSHS_LINE_BLEN - 70;
2820     } else
2821         bpstart = 0;
2822     bpos = bpstart;
2823     prior_ascii_len = bpstart + (DSHS_BPL * 3) + 1;
2824     n = 0;
2825     memset(buff, ' ', DSHS_LINE_BLEN);
2826     buff[DSHS_LINE_BLEN] = '\0';
2827     if (bpstart > 0)
2828         memcpy(buff, leadin, bpstart);
2829     for (k = 0; k < len; k++) {
2830         c = *p++;
2831         if (bpos == (bpstart + ((DSHS_BPL / 2) * 3)))
2832             bpos++;     /* for extra space in middle of each line's hex */
2833         scnpr(buff + bpos, (int)sizeof(buff) - bpos, "%.2x",
2834               (int)(unsigned char)c);
2835         buff[bpos + 2] = ' ';
2836         if (want_ascii)
2837             a[k % DSHS_BPL] = my_isprint(c) ? c : '.';
2838         if ((k > 0) && (0 == ((k + 1) % DSHS_BPL))) {
2839             trimTrailingSpaces(buff);
2840             if (want_ascii) {
2841                 n += scnpr(b + n, b_len - n, "%-*s   %s\n", prior_ascii_len,
2842                            buff, a);
2843                 memset(a, ' ', DSHS_BPL);
2844             } else
2845                 n += scnpr(b + n, b_len - n, "%s\n", buff);
2846             if (n >= (b_len - 1))
2847                 return n;
2848             memset(buff, ' ', DSHS_LINE_BLEN);
2849             bpos = bpstart;
2850             if (bpstart > 0)
2851                 memcpy(buff, leadin, bpstart);
2852         } else
2853             bpos += 3;
2854     }
2855     if (bpos > bpstart) {
2856         trimTrailingSpaces(buff);
2857         if (want_ascii)
2858             n += scnpr(b + n, b_len - n, "%-*s   %s\n", prior_ascii_len,
2859                        buff, a);
2860         else
2861             n += scnpr(b + n, b_len - n, "%s\n", buff);
2862     }
2863     return n;
2864 }
2865 
2866 void
hex2stdout(const uint8_t * b_str,int len,int no_ascii)2867 hex2stdout(const uint8_t * b_str, int len, int no_ascii)
2868 {
2869     dStrHex((const char *)b_str, len, no_ascii);
2870 }
2871 
2872 void
hex2stderr(const uint8_t * b_str,int len,int no_ascii)2873 hex2stderr(const uint8_t * b_str, int len, int no_ascii)
2874 {
2875     dStrHexErr((const char *)b_str, len, no_ascii);
2876 }
2877 
2878 int
hex2str(const uint8_t * b_str,int len,const char * leadin,int format,int b_len,char * b)2879 hex2str(const uint8_t * b_str, int len, const char * leadin, int format,
2880         int b_len, char * b)
2881 {
2882     return dStrHexStr((const char *)b_str, len, leadin, format, b_len, b);
2883 }
2884 
2885 /* Returns true when executed on big endian machine; else returns false.
2886  * Useful for displaying ATA identify words (which need swapping on a
2887  * big endian machine). */
2888 bool
sg_is_big_endian()2889 sg_is_big_endian()
2890 {
2891     union u_t {
2892         uint16_t s;
2893         unsigned char c[sizeof(uint16_t)];
2894     } u;
2895 
2896     u.s = 0x0102;
2897     return (u.c[0] == 0x01);     /* The lowest address contains
2898                                     the most significant byte */
2899 }
2900 
2901 bool
sg_all_zeros(const uint8_t * bp,int b_len)2902 sg_all_zeros(const uint8_t * bp, int b_len)
2903 {
2904     if ((NULL == bp) || (b_len <= 0))
2905         return false;
2906     for (--b_len; b_len >= 0; --b_len) {
2907         if (0x0 != bp[b_len])
2908             return false;
2909     }
2910     return true;
2911 }
2912 
2913 bool
sg_all_ffs(const uint8_t * bp,int b_len)2914 sg_all_ffs(const uint8_t * bp, int b_len)
2915 {
2916     if ((NULL == bp) || (b_len <= 0))
2917         return false;
2918     for (--b_len; b_len >= 0; --b_len) {
2919         if (0xff != bp[b_len])
2920             return false;
2921     }
2922     return true;
2923 }
2924 
2925 static uint16_t
swapb_uint16(uint16_t u)2926 swapb_uint16(uint16_t u)
2927 {
2928     uint16_t r;
2929 
2930     r = (u >> 8) & 0xff;
2931     r |= ((u & 0xff) << 8);
2932     return r;
2933 }
2934 
2935 /* Note the ASCII-hex output goes to stdout. [Most other output from functions
2936  * in this file go to sg_warnings_strm (default stderr).]
2937  * 'no_ascii' allows for 3 output types:
2938  *     > 0     each line has address then up to 8 ASCII-hex 16 bit words
2939  *     = 0     in addition, the ASCI bytes pairs are listed to the right
2940  *     = -1    only the ASCII-hex words are listed (i.e. without address)
2941  *     = -2    only the ASCII-hex words, formatted for "hdparm --Istdin"
2942  *     < -2    same as -1
2943  * If 'swapb' is true then bytes in each word swapped. Needs to be set
2944  * for ATA IDENTIFY DEVICE response on big-endian machines. */
2945 void
dWordHex(const uint16_t * words,int num,int no_ascii,bool swapb)2946 dWordHex(const uint16_t* words, int num, int no_ascii, bool swapb)
2947 {
2948     const uint16_t * p = words;
2949     uint16_t c;
2950     char buff[82];
2951     unsigned char upp, low;
2952     int a = 0;
2953     const int bpstart = 3;
2954     const int cpstart = 52;
2955     int cpos = cpstart;
2956     int bpos = bpstart;
2957     int i, k, blen;
2958 
2959     if (num <= 0)
2960         return;
2961     blen = (int)sizeof(buff);
2962     memset(buff, ' ', 80);
2963     buff[80] = '\0';
2964     if (no_ascii < 0) {
2965         for (k = 0; k < num; k++) {
2966             c = *p++;
2967             if (swapb)
2968                 c = swapb_uint16(c);
2969             bpos += 5;
2970             scnpr(buff + bpos, blen - bpos, "%.4x", (unsigned int)c);
2971             buff[bpos + 4] = ' ';
2972             if ((k > 0) && (0 == ((k + 1) % 8))) {
2973                 if (-2 == no_ascii)
2974                     printf("%.39s\n", buff +8);
2975                 else
2976                     printf("%.47s\n", buff);
2977                 bpos = bpstart;
2978                 memset(buff, ' ', 80);
2979             }
2980         }
2981         if (bpos > bpstart) {
2982             if (-2 == no_ascii)
2983                 printf("%.39s\n", buff +8);
2984             else
2985                 printf("%.47s\n", buff);
2986         }
2987         return;
2988     }
2989     /* no_ascii>=0, start each line with address (offset) */
2990     k = scnpr(buff + 1, blen - 1, "%.2x", a);
2991     buff[k + 1] = ' ';
2992 
2993     for (i = 0; i < num; i++) {
2994         c = *p++;
2995         if (swapb)
2996             c = swapb_uint16(c);
2997         bpos += 5;
2998         scnpr(buff + bpos, blen - bpos, "%.4x", (unsigned int)c);
2999         buff[bpos + 4] = ' ';
3000         if (no_ascii) {
3001             buff[cpos++] = ' ';
3002             buff[cpos++] = ' ';
3003             buff[cpos++] = ' ';
3004         } else {
3005             upp = (c >> 8) & 0xff;
3006             low = c & 0xff;
3007             if (! my_isprint(upp))
3008                 upp = '.';
3009             buff[cpos++] = upp;
3010             if (! my_isprint(low))
3011                 low = '.';
3012             buff[cpos++] = low;
3013             buff[cpos++] = ' ';
3014         }
3015         if (cpos > (cpstart + 23)) {
3016             printf("%.76s\n", buff);
3017             bpos = bpstart;
3018             cpos = cpstart;
3019             a += 8;
3020             memset(buff, ' ', 80);
3021             k = scnpr(buff + 1, blen - 1, "%.2x", a);
3022             buff[k + 1] = ' ';
3023         }
3024     }
3025     if (cpos > cpstart)
3026         printf("%.76s\n", buff);
3027 }
3028 
3029 /* If the number in 'buf' can be decoded or the multiplier is unknown
3030  * then -1 is returned. Accepts a hex prefix (0x or 0X) or a decimal
3031  * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
3032  * Main (SI) multipliers supported: K, M, G. Ignore leading spaces and
3033  * tabs; accept comma, hyphen, space, tab and hash as terminator. */
3034 int
sg_get_num(const char * buf)3035 sg_get_num(const char * buf)
3036 {
3037     int res, num, n, len;
3038     unsigned int unum;
3039     char * cp;
3040     const char * b;
3041     char c = 'c';
3042     char c2 = '\0';     /* keep static checker happy */
3043     char c3 = '\0';     /* keep static checker happy */
3044     char lb[16];
3045 
3046     if ((NULL == buf) || ('\0' == buf[0]))
3047         return -1;
3048     len = strlen(buf);
3049     n = strspn(buf, " \t");
3050     if (n > 0) {
3051         if (n == len)
3052             return -1;
3053         buf += n;
3054         len -= n;
3055     }
3056     /* following hack to keep C++ happy */
3057     cp = strpbrk((char *)buf, " \t,#-");
3058     if (cp) {
3059         len = cp - buf;
3060         n = (int)sizeof(lb) - 1;
3061         len = (len < n) ? len : n;
3062         memcpy(lb, buf, len);
3063         lb[len] = '\0';
3064         b = lb;
3065     } else
3066         b = buf;
3067     if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) {
3068         res = sscanf(b + 2, "%x", &unum);
3069         num = unum;
3070     } else if ('H' == toupper((int)b[len - 1])) {
3071         res = sscanf(b, "%x", &unum);
3072         num = unum;
3073     } else
3074         res = sscanf(b, "%d%c%c%c", &num, &c, &c2, &c3);
3075     if (res < 1)
3076         return -1LL;
3077     else if (1 == res)
3078         return num;
3079     else {
3080         if (res > 2)
3081             c2 = toupper((int)c2);
3082         if (res > 3)
3083             c3 = toupper((int)c3);
3084         switch (toupper((int)c)) {
3085         case 'C':
3086             return num;
3087         case 'W':
3088             return num * 2;
3089         case 'B':
3090             return num * 512;
3091         case 'K':
3092             if (2 == res)
3093                 return num * 1024;
3094             if (('B' == c2) || ('D' == c2))
3095                 return num * 1000;
3096             if (('I' == c2) && (4 == res) && ('B' == c3))
3097                 return num * 1024;
3098             return -1;
3099         case 'M':
3100             if (2 == res)
3101                 return num * 1048576;
3102             if (('B' == c2) || ('D' == c2))
3103                 return num * 1000000;
3104             if (('I' == c2) && (4 == res) && ('B' == c3))
3105                 return num * 1048576;
3106             return -1;
3107         case 'G':
3108             if (2 == res)
3109                 return num * 1073741824;
3110             if (('B' == c2) || ('D' == c2))
3111                 return num * 1000000000;
3112             if (('I' == c2) && (4 == res) && ('B' == c3))
3113                 return num * 1073741824;
3114             return -1;
3115         case 'X':
3116             cp = (char *)strchr(b, 'x');
3117             if (NULL == cp)
3118                 cp = (char *)strchr(b, 'X');
3119             if (cp) {
3120                 n = sg_get_num(cp + 1);
3121                 if (-1 != n)
3122                     return num * n;
3123             }
3124             return -1;
3125         default:
3126             pr2ws("unrecognized multiplier\n");
3127             return -1;
3128         }
3129     }
3130 }
3131 
3132 /* If the number in 'buf' can not be decoded then -1 is returned. Accepts a
3133  * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is
3134  * assumed. Does not accept multipliers. Accept a comma (","), hyphen ("-"),
3135  * a whitespace or newline as terminator. */
3136 int
sg_get_num_nomult(const char * buf)3137 sg_get_num_nomult(const char * buf)
3138 {
3139     int res, len, num;
3140     unsigned int unum;
3141     char * commap;
3142 
3143     if ((NULL == buf) || ('\0' == buf[0]))
3144         return -1;
3145     len = strlen(buf);
3146     commap = (char *)strchr(buf + 1, ',');
3147     if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
3148         res = sscanf(buf + 2, "%x", &unum);
3149         num = unum;
3150     } else if (commap && ('H' == toupper((int)*(commap - 1)))) {
3151         res = sscanf(buf, "%x", &unum);
3152         num = unum;
3153     } else if ((NULL == commap) && ('H' == toupper((int)buf[len - 1]))) {
3154         res = sscanf(buf, "%x", &unum);
3155         num = unum;
3156     } else
3157         res = sscanf(buf, "%d", &num);
3158     if (1 == res)
3159         return num;
3160     else
3161         return -1;
3162 }
3163 
3164 /* If the number in 'buf' can be decoded or the multiplier is unknown
3165  * then -1LL is returned. Accepts a hex prefix (0x or 0X) or a decimal
3166  * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
3167  * Main (SI) multipliers supported: K, M, G, T, P. Ignore leading spaces
3168  * and tabs; accept comma, hyphen, space, tab and hash as terminator. */
3169 int64_t
sg_get_llnum(const char * buf)3170 sg_get_llnum(const char * buf)
3171 {
3172     int res, len, n;
3173     int64_t num, ll;
3174     uint64_t unum;
3175     char * cp;
3176     const char * b;
3177     char c = 'c';
3178     char c2 = '\0';     /* keep static checker happy */
3179     char c3 = '\0';     /* keep static checker happy */
3180     char lb[32];
3181 
3182     if ((NULL == buf) || ('\0' == buf[0]))
3183         return -1LL;
3184     len = strlen(buf);
3185     n = strspn(buf, " \t");
3186     if (n > 0) {
3187         if (n == len)
3188             return -1LL;
3189         buf += n;
3190         len -= n;
3191     }
3192     /* following hack to keep C++ happy */
3193     cp = strpbrk((char *)buf, " \t,#-");
3194     if (cp) {
3195         len = cp - buf;
3196         n = (int)sizeof(lb) - 1;
3197         len = (len < n) ? len : n;
3198         memcpy(lb, buf, len);
3199         lb[len] = '\0';
3200         b = lb;
3201     } else
3202         b = buf;
3203     if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) {
3204         res = sscanf(b + 2, "%" SCNx64 , &unum);
3205         num = unum;
3206     } else if ('H' == toupper((int)b[len - 1])) {
3207         res = sscanf(b, "%" SCNx64 , &unum);
3208         num = unum;
3209     } else
3210         res = sscanf(b, "%" SCNd64 "%c%c%c", &num, &c, &c2, &c3);
3211     if (res < 1)
3212         return -1LL;
3213     else if (1 == res)
3214         return num;
3215     else {
3216         if (res > 2)
3217             c2 = toupper((int)c2);
3218         if (res > 3)
3219             c3 = toupper((int)c3);
3220         switch (toupper((int)c)) {
3221         case 'C':
3222             return num;
3223         case 'W':
3224             return num * 2;
3225         case 'B':
3226             return num * 512;
3227         case 'K':
3228             if (2 == res)
3229                 return num * 1024;
3230             if (('B' == c2) || ('D' == c2))
3231                 return num * 1000;
3232             if (('I' == c2) && (4 == res) && ('B' == c3))
3233                 return num * 1024;
3234             return -1LL;
3235         case 'M':
3236             if (2 == res)
3237                 return num * 1048576;
3238             if (('B' == c2) || ('D' == c2))
3239                 return num * 1000000;
3240             if (('I' == c2) && (4 == res) && ('B' == c3))
3241                 return num * 1048576;
3242             return -1LL;
3243         case 'G':
3244             if (2 == res)
3245                 return num * 1073741824;
3246             if (('B' == c2) || ('D' == c2))
3247                 return num * 1000000000;
3248             if (('I' == c2) && (4 == res) && ('B' == c3))
3249                 return num * 1073741824;
3250             return -1LL;
3251         case 'T':
3252             if (2 == res)
3253                 return num * 1099511627776LL;
3254             if (('B' == c2) || ('D' == c2))
3255                 return num * 1000000000000LL;
3256             if (('I' == c2) && (4 == res) && ('B' == c3))
3257                 return num * 1099511627776LL;
3258             return -1LL;
3259         case 'P':
3260             if (2 == res)
3261                 return num * 1099511627776LL * 1024;
3262             if (('B' == c2) || ('D' == c2))
3263                 return num * 1000000000000LL * 1000;
3264             if (('I' == c2) && (4 == res) && ('B' == c3))
3265                 return num * 1099511627776LL * 1024;
3266             return -1LL;
3267         case 'X':
3268             cp = (char *)strchr(b, 'x');
3269             if (NULL == cp)
3270                 cp = (char *)strchr(b, 'X');
3271             if (cp) {
3272                 ll = sg_get_llnum(cp + 1);
3273                 if (-1LL != ll)
3274                     return num * ll;
3275             }
3276             return -1LL;
3277         default:
3278             pr2ws("unrecognized multiplier\n");
3279             return -1LL;
3280         }
3281     }
3282 }
3283 
3284 /* If the number in 'buf' can not be decoded then -1 is returned. Accepts a
3285  * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is
3286  * assumed. Does not accept multipliers. Accept a comma (","), hyphen ("-"),
3287  * a whitespace or newline as terminator. Only decimal numbers can represent
3288  * negative numbers and '-1' must be treated separately. */
3289 int64_t
sg_get_llnum_nomult(const char * buf)3290 sg_get_llnum_nomult(const char * buf)
3291 {
3292     int res, len;
3293     int64_t num;
3294     uint64_t unum;
3295 
3296     if ((NULL == buf) || ('\0' == buf[0]))
3297         return -1;
3298     len = strlen(buf);
3299     if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
3300         res = sscanf(buf + 2, "%" SCNx64 "", &unum);
3301         num = unum;
3302     } else if ('H' == toupper(buf[len - 1])) {
3303         res = sscanf(buf, "%" SCNx64 "", &unum);
3304         num = unum;
3305     } else
3306         res = sscanf(buf, "%" SCNd64 "", &num);
3307     return (1 == res) ? num : -1;
3308 }
3309 
3310 /* Extract character sequence from ATA words as in the model string
3311  * in a IDENTIFY DEVICE response. Returns number of characters
3312  * written to 'ochars' before 0 character is found or 'num' words
3313  * are processed. */
3314 int
sg_ata_get_chars(const uint16_t * word_arr,int start_word,int num_words,bool is_big_endian,char * ochars)3315 sg_ata_get_chars(const uint16_t * word_arr, int start_word,
3316                  int num_words, bool is_big_endian, char * ochars)
3317 {
3318     int k;
3319     uint16_t s;
3320     char a, b;
3321     char * op = ochars;
3322 
3323     for (k = start_word; k < (start_word + num_words); ++k) {
3324         s = word_arr[k];
3325         if (is_big_endian) {
3326             a = s & 0xff;
3327             b = (s >> 8) & 0xff;
3328         } else {
3329             a = (s >> 8) & 0xff;
3330             b = s & 0xff;
3331         }
3332         if (a == 0)
3333             break;
3334         *op++ = a;
3335         if (b == 0)
3336             break;
3337         *op++ = b;
3338     }
3339     return op - ochars;
3340 }
3341 
3342 int
pr2serr(const char * fmt,...)3343 pr2serr(const char * fmt, ...)
3344 {
3345     va_list args;
3346     int n;
3347 
3348     va_start(args, fmt);
3349     n = vfprintf(stderr, fmt, args);
3350     va_end(args);
3351     return n;
3352 }
3353 
3354 #ifdef SG_LIB_FREEBSD
3355 #include <sys/param.h>
3356 #elif defined(SG_LIB_WIN32)
3357 #include <windows.h>
3358 
3359 static bool got_page_size = false;
3360 static uint32_t win_page_size;
3361 #endif
3362 
3363 uint32_t
sg_get_page_size(void)3364 sg_get_page_size(void)
3365 {
3366 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
3367     return sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */
3368 #elif defined(SG_LIB_WIN32)
3369     if (! got_page_size) {
3370         SYSTEM_INFO si;
3371 
3372         GetSystemInfo(&si);
3373         win_page_size = si.dwPageSize;
3374         got_page_size = true;
3375     }
3376     return win_page_size;
3377 #elif defined(SG_LIB_FREEBSD)
3378     return PAGE_SIZE;
3379 #else
3380     return 4096;     /* give up, pick likely figure */
3381 #endif
3382 }
3383 
3384 /* Returns pointer to heap (or NULL) that is aligned to a align_to byte
3385  * boundary. Sends back *buff_to_free pointer in third argument that may be
3386  * different from the return value. If it is different then the *buff_to_free
3387  * pointer should be freed (rather than the returned value) when the heap is
3388  * no longer needed. If align_to is 0 then aligns to OS's page size. Sets all
3389  * returned heap to zeros. If num_bytes is 0 then set to page size. */
3390 uint8_t *
sg_memalign(uint32_t num_bytes,uint32_t align_to,uint8_t ** buff_to_free,bool vb)3391 sg_memalign(uint32_t num_bytes, uint32_t align_to, uint8_t ** buff_to_free,
3392             bool vb)
3393 {
3394     size_t psz;
3395     uint8_t * res;
3396 
3397     if (buff_to_free)   /* make sure buff_to_free is NULL if alloc fails */
3398         *buff_to_free = NULL;
3399     psz = (align_to > 0) ? align_to : sg_get_page_size();
3400     if (0 == num_bytes)
3401         num_bytes = psz;        /* ugly to handle otherwise */
3402 
3403 #ifdef HAVE_POSIX_MEMALIGN
3404     {
3405         int err;
3406         void * wp = NULL;
3407 
3408         err = posix_memalign(&wp, psz, num_bytes);
3409         if (err || (NULL == wp)) {
3410             pr2ws("%s: posix_memalign: error [%d], out of memory?\n",
3411                   __func__, err);
3412             return NULL;
3413         }
3414         memset(wp, 0, num_bytes);
3415         if (buff_to_free)
3416             *buff_to_free = (uint8_t *)wp;
3417         res = (uint8_t *)wp;
3418         if (vb) {
3419             pr2ws("%s: posix_ma, len=%d, ", __func__, num_bytes);
3420             if (buff_to_free)
3421                 pr2ws("wrkBuffp=%p, ", (void *)res);
3422             pr2ws("psz=%u, rp=%p\n", (unsigned int)psz, (void *)res);
3423         }
3424         return res;
3425     }
3426 #else
3427     {
3428         void * wrkBuff;
3429         sg_uintptr_t align_1 = psz - 1;
3430 
3431         wrkBuff = (uint8_t *)calloc(num_bytes + psz, 1);
3432         if (NULL == wrkBuff) {
3433             if (buff_to_free)
3434                 *buff_to_free = NULL;
3435             return NULL;
3436         } else if (buff_to_free)
3437             *buff_to_free = (uint8_t *)wrkBuff;
3438         res = (uint8_t *)(void *)
3439             (((sg_uintptr_t)wrkBuff + align_1) & (~align_1));
3440         if (vb) {
3441             pr2ws("%s: hack, len=%d, ", __func__, num_bytes);
3442             if (buff_to_free)
3443                 pr2ws("buff_to_free=%p, ", wrkBuff);
3444             pr2ws("align_1=%lu, rp=%p\n", (unsigned long)align_1, (void *)res);
3445         }
3446         return res;
3447     }
3448 #endif
3449 }
3450 
3451 const char *
sg_lib_version()3452 sg_lib_version()
3453 {
3454     return sg_lib_version_str;
3455 }
3456 
3457 
3458 #ifdef SG_LIB_MINGW
3459 /* Non Unix OSes distinguish between text and binary files.
3460    Set text mode on fd. Does nothing in Unix. Returns negative number on
3461    failure. */
3462 
3463 #include <unistd.h>
3464 #include <fcntl.h>
3465 
3466 int
sg_set_text_mode(int fd)3467 sg_set_text_mode(int fd)
3468 {
3469     return setmode(fd, O_TEXT);
3470 }
3471 
3472 /* Set binary mode on fd. Does nothing in Unix. Returns negative number on
3473    failure. */
3474 int
sg_set_binary_mode(int fd)3475 sg_set_binary_mode(int fd)
3476 {
3477     return setmode(fd, O_BINARY);
3478 }
3479 
3480 #else
3481 /* For Unix the following functions are dummies. */
3482 int
sg_set_text_mode(int fd)3483 sg_set_text_mode(int fd)
3484 {
3485     return fd;  /* fd should be >= 0 */
3486 }
3487 
3488 int
sg_set_binary_mode(int fd)3489 sg_set_binary_mode(int fd)
3490 {
3491     return fd;
3492 }
3493 
3494 #endif
3495