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