1*e66f4605Smlelstv /* $NetBSD: util.c,v 1.3 2023/02/02 08:21:32 mlelstv Exp $ */
21f5086ecSnonaka
31f5086ecSnonaka /*-
41f5086ecSnonaka * Copyright (c) 2017 Netflix, Inc
51f5086ecSnonaka * All rights reserved.
61f5086ecSnonaka *
71f5086ecSnonaka * Redistribution and use in source and binary forms, with or without
81f5086ecSnonaka * modification, are permitted provided that the following conditions
91f5086ecSnonaka * are met:
101f5086ecSnonaka * 1. Redistributions of source code must retain the above copyright
111f5086ecSnonaka * notice, this list of conditions and the following disclaimer.
121f5086ecSnonaka * 2. Redistributions in binary form must reproduce the above copyright
131f5086ecSnonaka * notice, this list of conditions and the following disclaimer in the
141f5086ecSnonaka * documentation and/or other materials provided with the distribution.
151f5086ecSnonaka *
161f5086ecSnonaka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
171f5086ecSnonaka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181f5086ecSnonaka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191f5086ecSnonaka * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
201f5086ecSnonaka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211f5086ecSnonaka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221f5086ecSnonaka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231f5086ecSnonaka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241f5086ecSnonaka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251f5086ecSnonaka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261f5086ecSnonaka * SUCH DAMAGE.
271f5086ecSnonaka */
281f5086ecSnonaka
291f5086ecSnonaka #include <sys/cdefs.h>
301f5086ecSnonaka #ifndef lint
31*e66f4605Smlelstv __RCSID("$NetBSD: util.c,v 1.3 2023/02/02 08:21:32 mlelstv Exp $");
321f5086ecSnonaka #if 0
331f5086ecSnonaka __FBSDID("$FreeBSD: head/sbin/nvmecontrol/util.c 320423 2017-06-27 20:24:25Z imp $");
341f5086ecSnonaka #endif
351f5086ecSnonaka #endif
361f5086ecSnonaka
371f5086ecSnonaka #include <sys/endian.h>
381f5086ecSnonaka
391f5086ecSnonaka #include <stdlib.h>
401f5086ecSnonaka #include <string.h>
411f5086ecSnonaka
421f5086ecSnonaka #include "nvmectl.h"
431f5086ecSnonaka #include "bn.h"
441f5086ecSnonaka
451f5086ecSnonaka void
nvme_strvis(u_char * dst,int dlen,const u_char * src,int slen)461f5086ecSnonaka nvme_strvis(u_char *dst, int dlen, const u_char *src, int slen)
471f5086ecSnonaka {
481f5086ecSnonaka #define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377')
491f5086ecSnonaka /* Trim leading and trailing blanks and NULs. */
501f5086ecSnonaka while (slen > 0 && STRVIS_ISWHITE(src[0]))
511f5086ecSnonaka ++src, --slen;
521f5086ecSnonaka while (slen > 0 && STRVIS_ISWHITE(src[slen - 1]))
531f5086ecSnonaka --slen;
541f5086ecSnonaka
551f5086ecSnonaka while (slen > 0) {
561f5086ecSnonaka if (*src < 0x20 || *src >= 0x80) {
571f5086ecSnonaka /* non-printable characters */
581f5086ecSnonaka dlen -= 4;
591f5086ecSnonaka if (dlen < 1)
601f5086ecSnonaka break;
611f5086ecSnonaka *dst++ = '\\';
621f5086ecSnonaka *dst++ = ((*src & 0300) >> 6) + '0';
631f5086ecSnonaka *dst++ = ((*src & 0070) >> 3) + '0';
641f5086ecSnonaka *dst++ = ((*src & 0007) >> 0) + '0';
651f5086ecSnonaka } else if (*src == '\\') {
661f5086ecSnonaka /* quote characters */
671f5086ecSnonaka dlen -= 2;
681f5086ecSnonaka if (dlen < 1)
691f5086ecSnonaka break;
701f5086ecSnonaka *dst++ = '\\';
711f5086ecSnonaka *dst++ = '\\';
721f5086ecSnonaka } else {
731f5086ecSnonaka /* normal characters */
741f5086ecSnonaka if (--dlen < 1)
751f5086ecSnonaka break;
761f5086ecSnonaka *dst++ = *src;
771f5086ecSnonaka }
781f5086ecSnonaka ++src, --slen;
791f5086ecSnonaka }
801f5086ecSnonaka
811f5086ecSnonaka *dst++ = 0;
821f5086ecSnonaka }
831f5086ecSnonaka
841f5086ecSnonaka #define METRIX_PREFIX_BUFSIZ 17
851f5086ecSnonaka #define NO_METRIX_PREFIX_BUFSIZ 42
861f5086ecSnonaka
87*e66f4605Smlelstv static void
unit_string(BIGNUM * bn,const char * unit,long scale,char * out,size_t len)88*e66f4605Smlelstv unit_string(BIGNUM *bn, const char *unit, long scale, char *out, size_t len)
89*e66f4605Smlelstv {
90*e66f4605Smlelstv size_t ulen = strlen(unit);
91*e66f4605Smlelstv uint8_t tmp[4];
92*e66f4605Smlelstv BN_CTX *ctx;
93*e66f4605Smlelstv BIGNUM *sn;
94*e66f4605Smlelstv
95*e66f4605Smlelstv if (6 + ulen + 3 >= len)
96*e66f4605Smlelstv return;
97*e66f4605Smlelstv
98*e66f4605Smlelstv if (scale > 1) {
99*e66f4605Smlelstv ctx = BN_CTX_new();
100*e66f4605Smlelstv if (ctx == NULL)
101*e66f4605Smlelstv return;
102*e66f4605Smlelstv
103*e66f4605Smlelstv tmp[0] = (scale >> 24) & 0xff;
104*e66f4605Smlelstv tmp[1] = (scale >> 16) & 0xff;
105*e66f4605Smlelstv tmp[2] = (scale >> 8) & 0xff;
106*e66f4605Smlelstv tmp[3] = scale & 0xff;
107*e66f4605Smlelstv
108*e66f4605Smlelstv sn = BN_bin2bn(tmp, sizeof(tmp), NULL);
109*e66f4605Smlelstv if (sn != NULL) {
110*e66f4605Smlelstv BN_mul(bn, bn, sn, ctx);
111*e66f4605Smlelstv BN_free(sn);
112*e66f4605Smlelstv }
113*e66f4605Smlelstv
114*e66f4605Smlelstv BN_CTX_free(ctx);
115*e66f4605Smlelstv }
116*e66f4605Smlelstv
117*e66f4605Smlelstv strncpy(out, " (", len);
118*e66f4605Smlelstv humanize_bignum(out+2, 6 + ulen, bn, unit, HN_AUTOSCALE, HN_DECIMAL);
119*e66f4605Smlelstv strncat(out, ")", len);
120*e66f4605Smlelstv }
121*e66f4605Smlelstv
1221f5086ecSnonaka void
print_bignum1(const char * title,uint64_t v[2],const char * suffix,const char * unit,long scale)123*e66f4605Smlelstv print_bignum1(const char *title, uint64_t v[2], const char *suffix,
124*e66f4605Smlelstv const char *unit, long scale)
1251f5086ecSnonaka {
1261f5086ecSnonaka char buf[64];
127*e66f4605Smlelstv char buf2[64];
1281f5086ecSnonaka uint8_t tmp[16];
1296ac76f5bSnonaka uint64_t h, l;
1306ac76f5bSnonaka
1316ac76f5bSnonaka #if _BYTE_ORDER != _LITTLE_ENDIAN
1326ac76f5bSnonaka /* Already Converted to host endian */
1336ac76f5bSnonaka h = v[0];
1346ac76f5bSnonaka l = v[1];
1356ac76f5bSnonaka memcpy(tmp, v, sizeof(tmp));
1366ac76f5bSnonaka #else
1376ac76f5bSnonaka h = v[1];
1386ac76f5bSnonaka l = v[0];
1391f5086ecSnonaka
1401f5086ecSnonaka tmp[ 0] = (h >> 56) & 0xff;
1411f5086ecSnonaka tmp[ 1] = (h >> 48) & 0xff;
1421f5086ecSnonaka tmp[ 2] = (h >> 40) & 0xff;
1431f5086ecSnonaka tmp[ 3] = (h >> 32) & 0xff;
1441f5086ecSnonaka tmp[ 4] = (h >> 24) & 0xff;
1451f5086ecSnonaka tmp[ 5] = (h >> 16) & 0xff;
1461f5086ecSnonaka tmp[ 6] = (h >> 8) & 0xff;
1471f5086ecSnonaka tmp[ 7] = h & 0xff;
1481f5086ecSnonaka tmp[ 8] = (l >> 56) & 0xff;
1491f5086ecSnonaka tmp[ 9] = (l >> 48) & 0xff;
1501f5086ecSnonaka tmp[10] = (l >> 40) & 0xff;
1511f5086ecSnonaka tmp[11] = (l >> 32) & 0xff;
1521f5086ecSnonaka tmp[12] = (l >> 24) & 0xff;
1531f5086ecSnonaka tmp[13] = (l >> 16) & 0xff;
1541f5086ecSnonaka tmp[14] = (l >> 8) & 0xff;
1551f5086ecSnonaka tmp[15] = l & 0xff;
1566ac76f5bSnonaka #endif
1571f5086ecSnonaka
1581f5086ecSnonaka buf[0] = '\0';
159*e66f4605Smlelstv buf2[0] = '\0';
160*e66f4605Smlelstv
1616ac76f5bSnonaka BIGNUM *bn = BN_bin2bn(tmp, sizeof(tmp), NULL);
1621f5086ecSnonaka if (bn != NULL) {
1631f5086ecSnonaka humanize_bignum(buf, METRIX_PREFIX_BUFSIZ + strlen(suffix),
164*e66f4605Smlelstv bn, suffix, HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE);
165*e66f4605Smlelstv if (unit)
166*e66f4605Smlelstv unit_string(bn, unit, scale, buf2, sizeof(buf2));
1671f5086ecSnonaka BN_free(bn);
1681f5086ecSnonaka }
1691f5086ecSnonaka if (buf[0] == '\0')
1706ac76f5bSnonaka snprintf(buf, sizeof(buf), "0x%016" PRIx64 "%016" PRIx64, h, l);
171*e66f4605Smlelstv printf("%-31s %s%s\n", title, buf, buf2);
172*e66f4605Smlelstv }
173*e66f4605Smlelstv
174*e66f4605Smlelstv void
print_bignum(const char * title,uint64_t v[2],const char * suffix)175*e66f4605Smlelstv print_bignum(const char *title, uint64_t v[2], const char *suffix)
176*e66f4605Smlelstv {
177*e66f4605Smlelstv print_bignum1(title, v, suffix, NULL, 1);
1781f5086ecSnonaka }
1791f5086ecSnonaka
1801f5086ecSnonaka /* "Missing" from endian.h */
1811f5086ecSnonaka uint64_t
le48dec(const void * pp)1821f5086ecSnonaka le48dec(const void *pp)
1831f5086ecSnonaka {
1841f5086ecSnonaka uint8_t const *p = (uint8_t const *)pp;
1851f5086ecSnonaka
1861f5086ecSnonaka return (((uint64_t)le16dec(p + 4) << 32) | le32dec(p));
1871f5086ecSnonaka }
188