1*1c05a6eaSAndriy Gapon /* 2*1c05a6eaSAndriy Gapon * CDDL HEADER START 3*1c05a6eaSAndriy Gapon * 4*1c05a6eaSAndriy Gapon * The contents of this file are subject to the terms of the 5*1c05a6eaSAndriy Gapon * Common Development and Distribution License (the "License"). 6*1c05a6eaSAndriy Gapon * You may not use this file except in compliance with the License. 7*1c05a6eaSAndriy Gapon * 8*1c05a6eaSAndriy Gapon * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1c05a6eaSAndriy Gapon * or http://www.opensolaris.org/os/licensing. 10*1c05a6eaSAndriy Gapon * See the License for the specific language governing permissions 11*1c05a6eaSAndriy Gapon * and limitations under the License. 12*1c05a6eaSAndriy Gapon * 13*1c05a6eaSAndriy Gapon * When distributing Covered Code, include this CDDL HEADER in each 14*1c05a6eaSAndriy Gapon * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1c05a6eaSAndriy Gapon * If applicable, add the following below this CDDL HEADER, with the 16*1c05a6eaSAndriy Gapon * fields enclosed by brackets "[]" replaced with your own identifying 17*1c05a6eaSAndriy Gapon * information: Portions Copyright [yyyy] [name of copyright owner] 18*1c05a6eaSAndriy Gapon * 19*1c05a6eaSAndriy Gapon * CDDL HEADER END 20*1c05a6eaSAndriy Gapon */ 21*1c05a6eaSAndriy Gapon 22*1c05a6eaSAndriy Gapon /* 23*1c05a6eaSAndriy Gapon * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24*1c05a6eaSAndriy Gapon * Copyright 2017 Jason king 25*1c05a6eaSAndriy Gapon */ 26*1c05a6eaSAndriy Gapon 27*1c05a6eaSAndriy Gapon #include <stdio.h> 28*1c05a6eaSAndriy Gapon #include <string.h> 29*1c05a6eaSAndriy Gapon #include <sys/types.h> 30*1c05a6eaSAndriy Gapon #include <sys/debug.h> 31*1c05a6eaSAndriy Gapon #include "libcmdutils.h" 32*1c05a6eaSAndriy Gapon 33*1c05a6eaSAndriy Gapon /* The largest suffix that can fit, aka an exabyte (2^60 / 10^18) */ 34*1c05a6eaSAndriy Gapon #define INDEX_MAX (6) 35*1c05a6eaSAndriy Gapon 36*1c05a6eaSAndriy Gapon /* Verify INDEX_MAX fits */ 37*1c05a6eaSAndriy Gapon CTASSERT(INDEX_MAX * 10 < sizeof (uint64_t) * 8); 38*1c05a6eaSAndriy Gapon 39*1c05a6eaSAndriy Gapon void 40*1c05a6eaSAndriy Gapon nicenum_scale(uint64_t n, size_t units, char *buf, size_t buflen, 41*1c05a6eaSAndriy Gapon uint32_t flags) 42*1c05a6eaSAndriy Gapon { 43*1c05a6eaSAndriy Gapon uint64_t divamt = 1024; 44*1c05a6eaSAndriy Gapon uint64_t divisor = 1; 45*1c05a6eaSAndriy Gapon int index = 0; 46*1c05a6eaSAndriy Gapon int rc = 0; 47*1c05a6eaSAndriy Gapon char u; 48*1c05a6eaSAndriy Gapon 49*1c05a6eaSAndriy Gapon if (units == 0) 50*1c05a6eaSAndriy Gapon units = 1; 51*1c05a6eaSAndriy Gapon 52*1c05a6eaSAndriy Gapon if (n > 0) { 53*1c05a6eaSAndriy Gapon n *= units; 54*1c05a6eaSAndriy Gapon if (n < units) 55*1c05a6eaSAndriy Gapon goto overflow; 56*1c05a6eaSAndriy Gapon } 57*1c05a6eaSAndriy Gapon 58*1c05a6eaSAndriy Gapon if (flags & NN_DIVISOR_1000) 59*1c05a6eaSAndriy Gapon divamt = 1000; 60*1c05a6eaSAndriy Gapon 61*1c05a6eaSAndriy Gapon /* 62*1c05a6eaSAndriy Gapon * This tries to find the suffix S(n) such that 63*1c05a6eaSAndriy Gapon * S(n) <= n < S(n+1), where S(n) = 2^(n*10) | 10^(3*n) 64*1c05a6eaSAndriy Gapon * (i.e. 1024/1000, 1,048,576/1,000,000, etc). Stop once S(n) 65*1c05a6eaSAndriy Gapon * is the largest prefix supported (i.e. don't bother computing 66*1c05a6eaSAndriy Gapon * and checking S(n+1). Since INDEX_MAX should be the largest 67*1c05a6eaSAndriy Gapon * suffix that fits (currently an exabyte), S(INDEX_MAX + 1) is 68*1c05a6eaSAndriy Gapon * never checked as it would overflow. 69*1c05a6eaSAndriy Gapon */ 70*1c05a6eaSAndriy Gapon while (index < INDEX_MAX) { 71*1c05a6eaSAndriy Gapon uint64_t newdiv = divisor * divamt; 72*1c05a6eaSAndriy Gapon 73*1c05a6eaSAndriy Gapon /* CTASSERT() guarantee these never trip */ 74*1c05a6eaSAndriy Gapon VERIFY3U(newdiv, >=, divamt); 75*1c05a6eaSAndriy Gapon VERIFY3U(newdiv, >=, divisor); 76*1c05a6eaSAndriy Gapon 77*1c05a6eaSAndriy Gapon if (n < newdiv) 78*1c05a6eaSAndriy Gapon break; 79*1c05a6eaSAndriy Gapon 80*1c05a6eaSAndriy Gapon divisor = newdiv; 81*1c05a6eaSAndriy Gapon index++; 82*1c05a6eaSAndriy Gapon } 83*1c05a6eaSAndriy Gapon 84*1c05a6eaSAndriy Gapon u = " KMGTPE"[index]; 85*1c05a6eaSAndriy Gapon 86*1c05a6eaSAndriy Gapon if (index == 0) { 87*1c05a6eaSAndriy Gapon rc = snprintf(buf, buflen, "%llu", n); 88*1c05a6eaSAndriy Gapon } else if (n % divisor == 0) { 89*1c05a6eaSAndriy Gapon /* 90*1c05a6eaSAndriy Gapon * If this is an even multiple of the base, always display 91*1c05a6eaSAndriy Gapon * without any decimal precision. 92*1c05a6eaSAndriy Gapon */ 93*1c05a6eaSAndriy Gapon rc = snprintf(buf, buflen, "%llu%c", n / divisor, u); 94*1c05a6eaSAndriy Gapon } else { 95*1c05a6eaSAndriy Gapon /* 96*1c05a6eaSAndriy Gapon * We want to choose a precision that reflects the best choice 97*1c05a6eaSAndriy Gapon * for fitting in 5 characters. This can get rather tricky 98*1c05a6eaSAndriy Gapon * when we have numbers that are very close to an order of 99*1c05a6eaSAndriy Gapon * magnitude. For example, when displaying 10239 (which is 100*1c05a6eaSAndriy Gapon * really 9.999K), we want only a single place of precision 101*1c05a6eaSAndriy Gapon * for 10.0K. We could develop some complex heuristics for 102*1c05a6eaSAndriy Gapon * this, but it's much easier just to try each combination 103*1c05a6eaSAndriy Gapon * in turn. 104*1c05a6eaSAndriy Gapon */ 105*1c05a6eaSAndriy Gapon int i; 106*1c05a6eaSAndriy Gapon for (i = 2; i >= 0; i--) { 107*1c05a6eaSAndriy Gapon if ((rc = snprintf(buf, buflen, "%.*f%c", i, 108*1c05a6eaSAndriy Gapon (double)n / divisor, u)) <= 5) 109*1c05a6eaSAndriy Gapon break; 110*1c05a6eaSAndriy Gapon } 111*1c05a6eaSAndriy Gapon } 112*1c05a6eaSAndriy Gapon 113*1c05a6eaSAndriy Gapon if (rc + 1 > buflen || rc < 0) 114*1c05a6eaSAndriy Gapon goto overflow; 115*1c05a6eaSAndriy Gapon 116*1c05a6eaSAndriy Gapon return; 117*1c05a6eaSAndriy Gapon 118*1c05a6eaSAndriy Gapon overflow: 119*1c05a6eaSAndriy Gapon /* prefer a more verbose message if possible */ 120*1c05a6eaSAndriy Gapon if (buflen > 10) 121*1c05a6eaSAndriy Gapon (void) strlcpy(buf, "<overflow>", buflen); 122*1c05a6eaSAndriy Gapon else 123*1c05a6eaSAndriy Gapon (void) strlcpy(buf, "??", buflen); 124*1c05a6eaSAndriy Gapon } 125*1c05a6eaSAndriy Gapon 126*1c05a6eaSAndriy Gapon void 127*1c05a6eaSAndriy Gapon nicenum(uint64_t num, char *buf, size_t buflen) 128*1c05a6eaSAndriy Gapon { 129*1c05a6eaSAndriy Gapon nicenum_scale(num, 1, buf, buflen, 0); 130*1c05a6eaSAndriy Gapon } 131