xref: /aosp_15_r20/external/sg3_utils/testing/tst_sg_lib.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1 /*
2  * Copyright (c) 2013-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 #include <unistd.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <string.h>
16 #include <getopt.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #define __STDC_FORMAT_MACROS 1
20 #include <inttypes.h>
21 
22 #include <time.h>
23 
24 #if defined(__GNUC__) && ! defined(SG_LIB_FREEBSD)
25 #include <byteswap.h>
26 #endif
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"     /* need this to see if HAVE_BYTESWAP_H */
30 #endif
31 
32 #include "sg_lib.h"
33 #include "sg_pr2serr.h"
34 
35 /* Uncomment the next two undefs to force use of the generic (i.e. shifting)
36  * unaligned functions (i.e. sg_get_* and sg_put_*). Use "-b 16|32|64
37  * -n 100m" to see the differences in timing. */
38 /* #undef HAVE_CONFIG_H */
39 /* #undef HAVE_BYTESWAP_H */
40 #include "sg_unaligned.h"
41 
42 /*
43  * A utility program to test sg_libs string handling, specifically
44  * related to snprintf().
45  */
46 
47 static const char * version_str = "1.17 20220717";
48 
49 
50 #define MY_NAME "tst_sg_lib"
51 
52 #define MAX_LINE_LEN 1024
53 
54 
55 static struct option long_options[] = {
56         {"byteswap",  required_argument, 0, 'b'},
57         {"exit", no_argument, 0, 'e'},
58         {"help", no_argument, 0, 'h'},
59         {"hex2",  no_argument, 0, 'H'},
60         {"json", optional_argument, 0, 'j'},
61         {"leadin",  required_argument, 0, 'l'},
62         {"num",  required_argument, 0, 'n'},
63         {"printf", no_argument, 0, 'p'},
64         {"sense", no_argument, 0, 's'},
65         {"unaligned", no_argument, 0, 'u'},
66         {"verbose", no_argument, 0, 'v'},
67         {"version", no_argument, 0, 'V'},
68         {0, 0, 0, 0},   /* sentinel */
69 };
70 
71 static const uint8_t desc_sense_data1[] = {
72    /* unrec_err, excessive_writes, sdat_ovfl, additional_len=? */
73     0x72, 0x1, 0x3, 0x2, 0x80, 0x0, 0x0, 12+12+8+4+8+4+28,
74    /* Information: 0x11223344556677bb */
75     0x0, 0xa, 0x80, 0x0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0xbb,
76    /* command specific: 0x3344556677bbccff */
77     0x1, 0xa, 0x0, 0x0, 0x33, 0x44, 0x55, 0x66, 0x77, 0xbb, 0xcc, 0xff,
78    /* sense key specific: SKSV=1, actual_count=257 (hex: 0x101) */
79     0x2, 0x6, 0x0, 0x0, 0x80, 0x1, 0x1, 0x0,
80    /* field replaceable code=0x45 */
81     0x3, 0x2, 0x0, 0x45,
82    /* another progress report indicator */
83     0xa, 0x6, 0x2, 0x1, 0x2, 0x0, 0x32, 0x01,
84    /* incorrect length indicator (ILI) */
85     0x5, 0x2, 0x0, 0x20,
86    /* user data segment referral */
87     0xb, 26, 0x1, 0x0,
88         0,0,0,1, 0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,
89                  0x1,0x2,0x3,0x4,0x55,0x6,0x7,0x8,
90         2,0,0x12,0x34,
91     };
92 
93 static const uint8_t desc_sense_data2[] = {
94    /* ill_req, inv fld in para list, additional_len=? */
95     0x72, 0x5, 0x26, 0x0, 0x0, 0x0, 0x0, 8+4,
96    /* sense key specific: SKSV=1, C/D*=0, bitp=7 bytep=34 */
97     0x2, 0x6, 0x0, 0x0, 0x8f, 0x0, 0x34, 0x0,
98    /* field replaceable code=0x45 */
99     0x3, 0x2, 0x0, 0x45,
100     };
101 
102 static const uint8_t desc_sense_data3[] = {
103    /* medium err, vibration induced ..., additional_len=? */
104     0x72, 0x3, 0x9, 0x5, 0x0, 0x0, 0x0, 32+16,
105    /* 0xd: block dev: sense key specific: SKSV=1, retry_count=257, fru=0x45
106     * info=0x1122334455, command_specific=0x1   */
107     0xd, 0x1e, 0xa0, 0x0, 0x80, 0x1, 0x1, 0x45,
108     0x0, 0x0, 0x0, 0x11, 0x22, 0x33, 0x44, 0x55,
109     0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
110     /* following sbc3 (standard) and sbc4r10 inconsistency; add padding */
111     0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
112     /* 0xe: reason: send_to_given+henceforth, lu, naa-5, 0x5333333000001f40 */
113     0xe, 0xe, 0x0, 0x1, 0x1, 0x3, 0x0, 0x8,
114         0x53, 0x33, 0x33, 0x30, 0x0, 0x0, 0x1f, 0x40,
115     };
116 
117 static const uint8_t desc_sense_data4[] = {
118    /* ill_req, inv fld in para list, additional_len=? */
119     0x72, 0x5, 0x26, 0x0, 0x0, 0x0, 0x0, 24,
120    /* Forwarded sense data, FSDT=0, sd_src=7, f_status=2 */
121     0xc, 22, 0x7, 0x2,
122    /* ill_req, inv fld in para list, additional_len=? */
123     0x72, 0x5, 0x26, 0x0, 0x0, 0x0, 0x0, 8+4,
124    /* sense key specific: SKSV=1, C/D*=0, bitp=7 bytep=34 */
125     0x2, 0x6, 0x0, 0x0, 0x8f, 0x0, 0x34, 0x0,
126    /* field replaceable code=0x45 */
127     0x3, 0x2, 0x0, 0x45,
128     };
129 
130 static const uint8_t desc_sense_data5[] = {
131    /* no_sense, ATA info available */
132     0x72, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x0, 14+14,
133    /* ATA descriptor extend=1 */
134     0x9, 0xc, 0x1, 0x0, 0x34, 0x12, 0x44, 0x11,
135     0x55, 0x22, 0x66, 0x33, 0x1, 0x0,
136    /* ATA descriptor extend=0 */
137     0x9, 0xc, 0x0, 0x0, 0x34, 0x12, 0x44, 0x11,
138     0x55, 0x22, 0x66, 0x33, 0x1, 0x0,
139     };
140 
141 static const uint8_t desc_sense_data6[] = {
142    /* UA, req, subsidiary binding */
143     0x72, 0x6, 0x3f, 0x1a, 0x0, 0x0, 0x0, 26+12+12,
144     /* 0xe: designator, reason: preferred admin lu, uuid */
145     0xe, 0x18, 0x0, 0x4, 0x1, 0xa, 0x0, 0x12,
146         0x10, 0x0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
147         0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
148         0xfe, 0xdc,
149     /* 0x0: Information(valid): lun */
150     0x0, 0xa, 0x80, 0x0,
151     0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
152     /* 0x1: Command specific: 0x1 */
153     0x1, 0xa, 0x0, 0x0,
154     0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
155     };
156 
157 static const char * leadin = NULL;
158 
159 
160 static void
usage()161 usage()
162 {
163     fprintf(stderr,
164             "Usage: tst_sg_lib [--exit] [--help] [--hex2] [--leadin=STR] "
165             "[--printf]\n"
166             "                  [--sense] [--unaligned] [--verbose] "
167             "[--version]\n"
168             "  where:\n"
169 #if defined(__GNUC__) && ! defined(SG_LIB_FREEBSD)
170             "    --byteswap=B|-b B    B is 16, 32 or 64; tests NUM "
171             "byteswaps\n"
172             "                         compared to sg_unaligned "
173             "equivalent\n"
174             "    --exit|-e          test exit status strings\n"
175 #else
176             "    --exit|-e          test exit status strings\n"
177 #endif
178             "    --help|-h          print out usage message\n"
179             "    --hex2|-H          test hex2* variants\n"
180             "    --leadin=STR|-l STR    every line output by --sense "
181             "should\n"
182             "                           be prefixed by STR\n"
183             "    --num=NUM|-n NUM    number of iterations (def=1)\n"
184             "    --printf|-p        test library printf variants\n"
185             "    --sense|-s         test sense data handling\n"
186             "    --unaligned|-u     test unaligned data handling\n"
187             "    --verbose|-v       increase verbosity\n"
188             "    --version|-V       print version string and exit\n\n"
189             "Test various parts of sg_lib, see options. Sense data tests "
190             "overlap\nsomewhat with examples/sg_sense_test .\n"
191            );
192 
193 }
194 
195 static char *
get_exit_status_str(int exit_status,bool longer,int b_len,char * b)196 get_exit_status_str(int exit_status, bool longer, int b_len, char * b)
197 {
198     int n;
199 
200     n = sg_scnpr(b, b_len, "  ES=%d: ", exit_status);
201     if (n >= (b_len - 1))
202         return b;
203     if (sg_exit2str(exit_status, longer, b_len - n, b + n)) {
204         n = (int)strlen(b);
205         if (n < (b_len - 1))
206             sg_scnpr(b + n, b_len - n, " [ok=true]");
207         return b;
208     } else
209         snprintf(b, b_len, "  No ES string for %d%s", exit_status,
210                  (longer ? " [ok=false]" : ""));
211     return b;
212 }
213 
214 static uint8_t arr[64];
215 
216 #define OFF 7   /* in byteswap mode, can test different alignments (def: 8) */
217 
218 int
main(int argc,char * argv[])219 main(int argc, char * argv[])
220 {
221     bool as_json = false;
222     bool do_exit_status = false;
223     bool ok;
224     int k, c, n, len;
225     int byteswap_sz = 0;
226     int do_hex2 = 0;
227     int do_num = 1;
228     int do_printf = 0;
229     int do_sense = 0;
230     int do_unaligned = 0;
231     int did_something = 0;
232     int vb = 0;
233     int ret = 0;
234     sgj_opaque_p jop = NULL;
235     sgj_opaque_p jo2p;
236     sgj_state json_st SG_C_CPP_ZERO_INIT;
237     sgj_state * jsp = &json_st;
238     char b[2048];
239     char bb[256];
240     const int b_len = sizeof(b);
241 
242     while (1) {
243         int option_index = 0;
244 
245         c = getopt_long(argc, argv, "b:ehHj::l:n:psuvV", long_options,
246                         &option_index);
247         if (c == -1)
248             break;
249 
250         switch (c) {
251         case 'b':
252             byteswap_sz = sg_get_num(optarg);
253             if (! ((16 == byteswap_sz) || (32 == byteswap_sz) ||
254                    (64 == byteswap_sz))) {
255                 fprintf(stderr, "--byteswap= requires 16, 32 or 64\n");
256                 return 1;
257             }
258             break;
259         case 'e':
260             do_exit_status = true;
261             break;
262         case 'h':
263         case '?':
264             usage();
265             return 0;
266         case 'H':
267             ++do_hex2;
268             break;
269         case 'j':
270             if (! sgj_init_state(&json_st, optarg)) {
271                 pr2serr("bad argument to --json= option, unrecognized "
272                         "character '%c'\n", json_st.first_bad_char);
273                 return SG_LIB_SYNTAX_ERROR;
274             }
275             break;
276 
277         case 'l':
278             leadin = optarg;
279             break;
280         case 'n':
281             do_num = sg_get_num(optarg);
282             if (do_num < 0) {
283                 fprintf(stderr, "--num= unable decode argument as number\n");
284                 return 1;
285             }
286             break;
287         case 'p':
288             ++do_printf;
289             break;
290         case 's':
291             ++do_sense;
292             break;
293         case 'u':
294             ++do_unaligned;
295             break;
296         case 'v':
297             ++vb;
298             break;
299         case 'V':
300             fprintf(stderr, "version: %s\n", version_str);
301             return 0;
302         default:
303             fprintf(stderr, "unrecognised switch code 0x%x ??\n", c);
304             usage();
305             return 1;
306         }
307     }
308     if (optind < argc) {
309         if (optind < argc) {
310             for (; optind < argc; ++optind)
311                 fprintf(stderr, "Unexpected extra argument: %s\n",
312                         argv[optind]);
313             usage();
314             return 1;
315         }
316     }
317 
318     as_json = json_st.pr_as_json;
319     if (as_json)
320         jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp);
321 
322     if (do_exit_status) {
323         ++did_something;
324 
325         printf("Test Exit Status strings (add -v for long version):\n");
326         printf("  No error (es=0): %s\n",
327                sg_get_category_sense_str(0, b_len, b, vb));
328         ok = sg_exit2str(0, true, b_len, b);
329         printf("  No error (force verbose): %s\n", b);
330         if (vb)
331             printf("    for previous line sg_exit2str() returned: %s\n",
332                    (ok ? "true" : "false"));
333         printf("%s\n", get_exit_status_str(1, (vb > 0), b_len, b));
334         printf("%s\n", get_exit_status_str(2, (vb > 0), b_len, b));
335         printf("%s\n", get_exit_status_str(3, (vb > 0), b_len, b));
336         printf("%s\n", get_exit_status_str(4, (vb > 0), b_len, b));
337         printf("%s\n", get_exit_status_str(5, (vb > 0), b_len, b));
338         printf("%s\n", get_exit_status_str(6, (vb > 0), b_len, b));
339         printf("%s\n", get_exit_status_str(7, (vb > 0), b_len, b));
340         printf("%s\n", get_exit_status_str(8, (vb > 0), b_len, b));
341         printf("%s\n", get_exit_status_str(25, (vb > 0), b_len, b));
342         printf("%s\n", get_exit_status_str(33, (vb > 0), b_len, b));
343         printf("%s\n", get_exit_status_str(36, (vb > 0), b_len, b));
344         printf("%s\n", get_exit_status_str(48, (vb > 0), b_len, b));
345         printf("%s\n", get_exit_status_str(50, (vb > 0), b_len, b));
346         printf("%s\n", get_exit_status_str(51, (vb > 0), b_len, b));
347         printf("%s\n", get_exit_status_str(96, (vb > 0), b_len, b));
348         printf("%s\n", get_exit_status_str(97, (vb > 0), b_len, b));
349         printf("%s\n", get_exit_status_str(97, (vb > 0), b_len, b));
350         printf("%s\n", get_exit_status_str(255, (vb > 0), b_len, b));
351         printf("%s\n", get_exit_status_str(-1, (vb > 0), b_len, b));
352 
353         printf("\n");
354     }
355 
356     if (do_sense ) {
357         ++did_something;
358         if (as_json) {
359             jo2p = sgj_named_subobject_r(jsp, jop, "desc_sense_data__test1");
360             sgj_js_sense(jsp, jo2p,  desc_sense_data1,
361                          (int)sizeof(desc_sense_data1));
362         } else {
363             printf("desc_sense_data test1:\n");
364             sg_print_sense(leadin, desc_sense_data1,
365                            (int)sizeof(desc_sense_data1), vb);
366             printf("\n");
367         }
368 #if 1
369         if (as_json) {
370             sgj_js_str_out(jsp, "sg_get_sense_str(ds_data1)", 999);
371             sg_get_sense_str(leadin, desc_sense_data1,
372                              sizeof(desc_sense_data1), vb, b_len, b);
373             sgj_js_str_out(jsp, b, strlen(b));
374 
375         } else {
376             printf("sg_get_sense_str(ds_data1):\n");
377             sg_get_sense_str(leadin, desc_sense_data1,
378                              sizeof(desc_sense_data1), vb, b_len, b);
379             printf("sg_get_sense_str: strlen(b)->%u\n", (uint32_t)strlen(b));
380             printf("%s", b);
381             printf("\n");
382         }
383 #endif
384         if (as_json) {
385             jo2p = sgj_named_subobject_r(jsp, jop, "desc_sense_data__test2");
386             sgj_js_sense(jsp, jo2p,  desc_sense_data2,
387                          (int)sizeof(desc_sense_data2));
388         } else {
389             printf("desc_sense_data test2\n");
390             sg_print_sense(leadin, desc_sense_data2,
391                            (int)sizeof(desc_sense_data2), vb);
392             printf("\n");
393         }
394         if (as_json) {
395             jo2p = sgj_named_subobject_r(jsp, jop,
396                                          "desc_sense_block_combo_test3");
397             sgj_js_sense(jsp, jo2p,  desc_sense_data3,
398                             (int)sizeof(desc_sense_data3));
399         } else {
400             printf("desc_sense block dev combo plus designator test3\n");
401             sg_print_sense(leadin, desc_sense_data3,
402                            (int)sizeof(desc_sense_data3), vb);
403             printf("\n");
404         }
405         if (as_json) {
406             jo2p = sgj_named_subobject_r(jsp, jop,
407                                          "desc_sense_forwarded_sense_test4");
408             sgj_js_sense(jsp, jo2p,  desc_sense_data4,
409                          (int)sizeof(desc_sense_data4));
410         } else {
411             printf("desc_sense forwarded sense test4\n");
412             sg_print_sense(leadin, desc_sense_data4,
413                            (int)sizeof(desc_sense_data4), vb);
414             printf("\n");
415         }
416         if (as_json) {
417             jo2p = sgj_named_subobject_r(jsp, jop,
418                                          "desc_sense_ata_info_test5");
419             sgj_js_sense(jsp, jo2p,  desc_sense_data5,
420                          (int)sizeof(desc_sense_data5));
421         } else {
422             printf("desc_sense ATA Info test5\n");
423             sg_print_sense(leadin, desc_sense_data5,
424                            (int)sizeof(desc_sense_data5), vb);
425             printf("\n");
426         }
427         if (as_json) {
428             jo2p = sgj_named_subobject_r(jsp, jop,
429                                          "desc_sense_ua_binding_test6");
430             sgj_js_sense(jsp, jo2p,  desc_sense_data6,
431                          (int)sizeof(desc_sense_data6));
432         } else {
433             printf("desc_sense UA subsidiary binding changed test6\n");
434             sg_print_sense(leadin, desc_sense_data6,
435                            (int)sizeof(desc_sense_data6), vb);
436             printf("\n");
437             printf("\n");
438         }
439     }
440 
441     if (do_printf) {
442         ++did_something;
443         printf("Testing sg_scnpr():\n");
444         b[0] = '\0';
445         len = b_len;
446         n = sg_scnpr(b, len, "%s", "test");
447         printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n",
448                len, n, (uint32_t)strlen(b));
449         if (strlen(b) > 0)
450             printf("Resulting string: %s\n", b);
451 
452         b[0] = '\0';
453         len = -1;
454         n = sg_scnpr(b, len, "%s", "test");
455         printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n",
456                len, n, (uint32_t)strlen(b));
457         if (strlen(b) > 0)
458             printf("Resulting string: %s\n", b);
459 
460         b[0] = '\0';
461         len = 0;
462         n = sg_scnpr(b, len, "%s", "test");
463         printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n",
464                len, n, (uint32_t)strlen(b));
465         if (strlen(b) > 0)
466             printf("Resulting string: %s\n", b);
467 
468         b[0] = '\0';
469         len = 1;
470         n = sg_scnpr(b, len, "%s", "test");
471         printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n",
472                len, n, (uint32_t)strlen(b));
473         if (strlen(b) > 0)
474             printf("Resulting string: %s\n", b);
475 
476         b[0] = '\0';
477         len = 2;
478         n = sg_scnpr(b, len, "%s", "test");
479         printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n",
480                len, n, (uint32_t)strlen(b));
481         if (strlen(b) > 0)
482             printf("Resulting string: %s\n", b);
483 
484         b[0] = '\0';
485         len = 3;
486         n = sg_scnpr(b, len, "%s", "test");
487         printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n",
488                len, n, (uint32_t)strlen(b));
489         if (strlen(b) > 0)
490             printf("Resulting string: %s\n", b);
491 
492         b[0] = '\0';
493         len = 4;
494         n = sg_scnpr(b, len, "%s", "test");
495         printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n",
496                len, n, (uint32_t)strlen(b));
497         if (strlen(b) > 0)
498             printf("Resulting string: %s\n", b);
499 
500         b[0] = '\0';
501         len = 5;
502         n = sg_scnpr(b, len, "%s", "test");
503         printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n",
504                len, n, (uint32_t)strlen(b));
505         if (strlen(b) > 0)
506             printf("Resulting string: %s\n", b);
507 
508         b[0] = '\0';
509         len = 6;
510         n = sg_scnpr(b, len, "%s", "test");
511         printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n",
512                len, n, (uint32_t)strlen(b));
513         if (strlen(b) > 0)
514             printf("Resulting string: %s\n", b);
515 
516         b[0] = '\0';
517         len = 7;
518         n = sg_scnpr(b, len, "%s", "test");
519         printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n",
520                len, n, (uint32_t)strlen(b));
521         if (strlen(b) > 0)
522             printf("Resulting string: %s\n", b);
523     }
524     if (do_hex2) {
525         uint8_t b[] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
526                        0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
527                        0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58};
528 
529         ++did_something;
530         for (k = 0; k < 19; ++k) {
531             printf("k=%d:\n", k);
532             hex2stdout(b, k, 0);
533             hex2str(b, k, "h2str0: ", 0, sizeof(bb), bb);
534             printf("%s", bb);
535             hex2stdout(b, k, 1);
536             hex2str(b, k, "h2str1: ", 1, sizeof(bb), bb);
537             printf("%s", bb);
538             hex2str(b, k, "h2str2: ", 2, sizeof(bb), bb);
539             printf("%s\n", bb);
540             hex2stdout(b, k, -1);
541             printf("\n");
542         }
543     }
544     if (do_unaligned) {
545         uint16_t u16 = 0x55aa;
546         uint16_t u16r;
547         uint32_t u24 = 0x224488;
548         uint32_t u24r;
549         uint32_t u32 = 0x224488aa;
550         uint32_t u32r;
551         uint64_t u48 = 0x112233445566ULL;
552         uint64_t u48r;
553         uint64_t u64 = 0x1122334455667788ULL;
554         uint64_t u64r;
555         uint8_t u8[64];
556 
557         ++did_something;
558         if (vb)
559             memset(u8, 0, sizeof(u8));
560         printf("u16=0x%" PRIx16 "\n", u16);
561         sg_put_unaligned_le16(u16, u8);
562         printf("  le16:\n");
563         hex2stdout(u8, vb ? 10 : 2, -1);
564         u16r = sg_get_unaligned_le16(u8);
565         printf("  u16r=0x%" PRIx16 "\n", u16r);
566         sg_put_unaligned_be16(u16, u8);
567         printf("  be16:\n");
568         hex2stdout(u8, vb ? 10 : 2, -1);
569         u16r = sg_get_unaligned_be16(u8);
570         printf("  u16r=0x%" PRIx16 "\n\n", u16r);
571 
572         printf("u24=0x%" PRIx32 "\n", u24);
573         sg_put_unaligned_le24(u24, u8);
574         printf("  le24:\n");
575         hex2stdout(u8, vb ? 10 : 3, -1);
576         u24r = sg_get_unaligned_le24(u8);
577         printf("  u24r=0x%" PRIx32 "\n", u24r);
578         sg_put_unaligned_be24(u24, u8);
579         printf("  be24:\n");
580         hex2stdout(u8, vb ? 10 : 3, -1);
581         u24r = sg_get_unaligned_be24(u8);
582         printf("  u24r=0x%" PRIx32 "\n\n", u24r);
583 
584         printf("u32=0x%" PRIx32 "\n", u32);
585         sg_put_unaligned_le32(u32, u8);
586         printf("  le32:\n");
587         hex2stdout(u8, vb ? 10 : 4, -1);
588         u32r = sg_get_unaligned_le32(u8);
589         printf("  u32r=0x%" PRIx32 "\n", u32r);
590         sg_put_unaligned_be32(u32, u8);
591         printf("  be32:\n");
592         hex2stdout(u8, vb ? 10 : 4, -1);
593         u32r = sg_get_unaligned_be32(u8);
594         printf("  u32r=0x%" PRIx32 "\n\n", u32r);
595 
596         printf("u48=0x%" PRIx64 "\n", u48);
597         sg_put_unaligned_le48(u48, u8);
598         printf("  le48:\n");
599         hex2stdout(u8, vb ? 10 : 6, -1);
600         u48r = sg_get_unaligned_le48(u8);
601         printf("  u48r=0x%" PRIx64 "\n", u48r);
602         sg_put_unaligned_be48(u48, u8);
603         printf("  be48:\n");
604         hex2stdout(u8, vb ? 10 : 6, -1);
605         u48r = sg_get_unaligned_be48(u8);
606         printf("  u48r=0x%" PRIx64 "\n\n", u48r);
607 
608         printf("u64=0x%" PRIx64 "\n", u64);
609         sg_put_unaligned_le64(u64, u8);
610         printf("  le64:\n");
611         hex2stdout(u8, vb ? 10 : 8, -1);
612         u64r = sg_get_unaligned_le64(u8);
613         printf("  u64r=0x%" PRIx64 "\n", u64r);
614         sg_put_unaligned_be64(u64, u8);
615         printf("  be64:\n");
616         hex2stdout(u8, vb ? 10 : 8, -1);
617         u64r = sg_get_unaligned_be64(u8);
618         printf("  u64r=0x%" PRIx64 "\n\n", u64r);
619 
620         printf("  be[v=8 bytes]:\n");
621         hex2stdout(u8, vb ? 10 : 8, -1);
622         u64r = sg_get_unaligned_be(8, u8);
623         printf("  u64r[v=8 bytes]=0x%" PRIx64 "\n", u64r);
624         printf("  le[v=8 bytes]:\n");
625         hex2stdout(u8, vb ? 10 : 8, -1);
626         u64r = sg_get_unaligned_le(8, u8);
627         printf("  u64r[v=8 bytes]=0x%" PRIx64 "\n\n", u64r);
628     }
629 
630 #if defined(__GNUC__) && ! defined(SG_LIB_FREEBSD)
631     if (byteswap_sz > 0) {
632         uint32_t elapsed_msecs;
633         uint16_t count16 = 0;
634         uint32_t count32 = 0;
635         uint64_t count64 = 0;
636         struct timespec start_tm, end_tm;
637 
638         ++did_something;
639         if (0 != clock_gettime(CLOCK_MONOTONIC, &start_tm)) {
640             perror("clock_gettime(CLOCK_MONOTONIC)\n");
641             return 1;
642         }
643         for (k = 0; k < do_num; ++k) {
644             switch (byteswap_sz) {
645             case 16:
646                 sg_put_unaligned_be16(count16 + 1, arr + OFF);
647                 count16 = sg_get_unaligned_be16(arr + OFF);
648                 break;
649             case 32:
650                 sg_put_unaligned_be32(count32 + 1, arr + OFF);
651                 count32 = sg_get_unaligned_be32(arr + OFF);
652                 break;
653             case 64:
654                 sg_put_unaligned_be64(count64 + 1, arr + OFF);
655                 count64 = sg_get_unaligned_be64(arr + OFF);
656                 break;
657             default:
658                 break;
659             }
660         }
661         if (0 != clock_gettime(CLOCK_MONOTONIC, &end_tm)) {
662             perror("clock_gettime(CLOCK_MONOTONIC)\n");
663             return 1;
664         }
665         elapsed_msecs = (end_tm.tv_sec - start_tm.tv_sec) * 1000;
666         elapsed_msecs += (end_tm.tv_nsec - start_tm.tv_nsec) / 1000000;
667         if (16 == byteswap_sz)
668             printf("  last k=%d, last count16=%u\n", k, count16);
669         else if (32 == byteswap_sz)
670             printf("  last k=%d, last count32=%u\n", k, count32);
671         else
672             printf("  last k=%d, last count64=%" PRIu64 "\n", k, count64);
673         printf("Unaligned elapsed milliseconds: %u\n", elapsed_msecs);
674         count16 = 0;
675         count32 = 0;
676         count64 = 0;
677 
678         if (0 != clock_gettime(CLOCK_MONOTONIC, &start_tm)) {
679             perror("clock_gettime(CLOCK_MONOTONIC)\n");
680             return 1;
681         }
682         for (k = 0; k < do_num; ++k) {
683             switch (byteswap_sz) {
684             case 16:
685                 count16 = bswap_16(count16 + 1);
686                 memcpy(arr + OFF, &count16, 2);
687                 memcpy(&count16, arr + OFF, 2);
688                 count16 = bswap_16(count16);
689                 break;
690             case 32:
691                 count32 = bswap_32(count32 + 1);
692                 memcpy(arr + OFF, &count32, 4);
693                 memcpy(&count32, arr + OFF, 4);
694                 count32 = bswap_32(count32);
695                 break;
696             case 64:
697                 count64 = bswap_64(count64 + 1);
698                 memcpy(arr + OFF, &count64, 8);
699                 memcpy(&count64, arr + OFF, 8);
700                 count64 = bswap_64(count64);
701                 break;
702             default:
703                 break;
704             }
705         }
706         if (0 != clock_gettime(CLOCK_MONOTONIC, &end_tm)) {
707             perror("clock_gettime(CLOCK_MONOTONIC)\n");
708             return 1;
709         }
710         elapsed_msecs = (end_tm.tv_sec - start_tm.tv_sec) * 1000;
711         elapsed_msecs += (end_tm.tv_nsec - start_tm.tv_nsec) / 1000000;
712         if (16 == byteswap_sz)
713             printf("  last k=%d, last count16=%u\n", k, count16);
714         else if (32 == byteswap_sz)
715             printf("  last k=%d, last count32=%u\n", k, count32);
716         else
717             printf("  last k=%d, last count64=%" PRIu64 "\n", k, count64);
718         printf("Byteswap/memcpy elapsed milliseconds: %u\n", elapsed_msecs);
719         count16 = 0;
720         count32 = 0;
721         count64 = 0;
722     }
723 #endif
724 
725     if (0 == did_something)
726         printf("Looks like no tests done, check usage with '-h'\n");
727     ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
728     if (as_json) {
729         if (0 == do_hex2)
730             sgj_js2file(jsp, NULL, ret, stdout);
731         sgj_finish(jsp);
732     }
733     return ret;
734 }
735