aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorAndriy Gapon <avg@FreeBSD.org>2017-10-26 16:20:47 +0000
committerAndriy Gapon <avg@FreeBSD.org>2017-10-26 16:20:47 +0000
commitfcf62a28091fff46b3fc89729b9eeedbf8974dda (patch)
treef3644cf1007865c662757739b7a0f4aa2967828d /lib
parente0cb71a82ff0939501a50dd2ff4c7afd94efe665 (diff)
downloadsrc-fcf62a28091fff46b3fc89729b9eeedbf8974dda.tar.gz
src-fcf62a28091fff46b3fc89729b9eeedbf8974dda.zip
640 number_to_scaled_string is duplicated in several commands
illumos/illumos-gate@0a0551200ecbcd4f1b17560acaeeb7b6c8b0090e https://github.com/illumos/illumos-gate/commit/0a0551200ecbcd4f1b17560acaeeb7b6c8b0090e https://www.illumos.org/issues/640 du(1), df(1m), ls(1), and swap(1m) all include a copy (it appears literally copied) of the 'number_to_scaled_string' function in their source. This should be moved to a shared library and all 4 commands should use this instead. Reviewed by: Sebastian Wiedenroth <wiedi@frubar.net> Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Yuri Pankov <yuripv@gmx.com> Approved by: Dan McDonald <danmcd@joyent.com> Author: Jason King <jason.brian.king@gmail.com>
Notes
Notes: svn path=/vendor/illumos/dist/; revision=325013
Diffstat (limited to 'lib')
-rw-r--r--lib/libcmdutils/common/nicenum.c130
-rw-r--r--lib/libzfs/common/libzfs_util.c38
-rw-r--r--lib/libzpool/common/sys/zfs_context.h2
-rw-r--r--lib/libzpool/common/util.c47
4 files changed, 144 insertions, 73 deletions
diff --git a/lib/libcmdutils/common/nicenum.c b/lib/libcmdutils/common/nicenum.c
new file mode 100644
index 000000000000..8e3202f79270
--- /dev/null
+++ b/lib/libcmdutils/common/nicenum.c
@@ -0,0 +1,130 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Jason king
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/debug.h>
+#include "libcmdutils.h"
+
+/* The largest suffix that can fit, aka an exabyte (2^60 / 10^18) */
+#define INDEX_MAX (6)
+
+/* Verify INDEX_MAX fits */
+CTASSERT(INDEX_MAX * 10 < sizeof (uint64_t) * 8);
+
+void
+nicenum_scale(uint64_t n, size_t units, char *buf, size_t buflen,
+ uint32_t flags)
+{
+ uint64_t divamt = 1024;
+ uint64_t divisor = 1;
+ int index = 0;
+ int rc = 0;
+ char u;
+
+ if (units == 0)
+ units = 1;
+
+ if (n > 0) {
+ n *= units;
+ if (n < units)
+ goto overflow;
+ }
+
+ if (flags & NN_DIVISOR_1000)
+ divamt = 1000;
+
+ /*
+ * This tries to find the suffix S(n) such that
+ * S(n) <= n < S(n+1), where S(n) = 2^(n*10) | 10^(3*n)
+ * (i.e. 1024/1000, 1,048,576/1,000,000, etc). Stop once S(n)
+ * is the largest prefix supported (i.e. don't bother computing
+ * and checking S(n+1). Since INDEX_MAX should be the largest
+ * suffix that fits (currently an exabyte), S(INDEX_MAX + 1) is
+ * never checked as it would overflow.
+ */
+ while (index < INDEX_MAX) {
+ uint64_t newdiv = divisor * divamt;
+
+ /* CTASSERT() guarantee these never trip */
+ VERIFY3U(newdiv, >=, divamt);
+ VERIFY3U(newdiv, >=, divisor);
+
+ if (n < newdiv)
+ break;
+
+ divisor = newdiv;
+ index++;
+ }
+
+ u = " KMGTPE"[index];
+
+ if (index == 0) {
+ rc = snprintf(buf, buflen, "%llu", n);
+ } else if (n % divisor == 0) {
+ /*
+ * If this is an even multiple of the base, always display
+ * without any decimal precision.
+ */
+ rc = snprintf(buf, buflen, "%llu%c", n / divisor, u);
+ } else {
+ /*
+ * We want to choose a precision that reflects the best choice
+ * for fitting in 5 characters. This can get rather tricky
+ * when we have numbers that are very close to an order of
+ * magnitude. For example, when displaying 10239 (which is
+ * really 9.999K), we want only a single place of precision
+ * for 10.0K. We could develop some complex heuristics for
+ * this, but it's much easier just to try each combination
+ * in turn.
+ */
+ int i;
+ for (i = 2; i >= 0; i--) {
+ if ((rc = snprintf(buf, buflen, "%.*f%c", i,
+ (double)n / divisor, u)) <= 5)
+ break;
+ }
+ }
+
+ if (rc + 1 > buflen || rc < 0)
+ goto overflow;
+
+ return;
+
+overflow:
+ /* prefer a more verbose message if possible */
+ if (buflen > 10)
+ (void) strlcpy(buf, "<overflow>", buflen);
+ else
+ (void) strlcpy(buf, "??", buflen);
+}
+
+void
+nicenum(uint64_t num, char *buf, size_t buflen)
+{
+ nicenum_scale(num, 1, buf, buflen, 0);
+}
diff --git a/lib/libzfs/common/libzfs_util.c b/lib/libzfs/common/libzfs_util.c
index bcb48094f65a..aba044add5e0 100644
--- a/lib/libzfs/common/libzfs_util.c
+++ b/lib/libzfs/common/libzfs_util.c
@@ -45,6 +45,7 @@
#include <sys/mnttab.h>
#include <sys/mntent.h>
#include <sys/types.h>
+#include <libcmdutils.h>
#include <libzfs.h>
#include <libzfs_core.h>
@@ -572,42 +573,7 @@ zfs_strdup(libzfs_handle_t *hdl, const char *str)
void
zfs_nicenum(uint64_t num, char *buf, size_t buflen)
{
- uint64_t n = num;
- int index = 0;
- char u;
-
- while (n >= 1024) {
- n /= 1024;
- index++;
- }
-
- u = " KMGTPE"[index];
-
- if (index == 0) {
- (void) snprintf(buf, buflen, "%llu", n);
- } else if ((num & ((1ULL << 10 * index) - 1)) == 0) {
- /*
- * If this is an even multiple of the base, always display
- * without any decimal precision.
- */
- (void) snprintf(buf, buflen, "%llu%c", n, u);
- } else {
- /*
- * We want to choose a precision that reflects the best choice
- * for fitting in 5 characters. This can get rather tricky when
- * we have numbers that are very close to an order of magnitude.
- * For example, when displaying 10239 (which is really 9.999K),
- * we want only a single place of precision for 10.0K. We could
- * develop some complex heuristics for this, but it's much
- * easier just to try each combination in turn.
- */
- int i;
- for (i = 2; i >= 0; i--) {
- if (snprintf(buf, buflen, "%.*f%c", i,
- (double)num / (1ULL << 10 * index), u) <= 5)
- break;
- }
- }
+ nicenum(num, buf, buflen);
}
void
diff --git a/lib/libzpool/common/sys/zfs_context.h b/lib/libzpool/common/sys/zfs_context.h
index 01c12b90a869..d8d1f8e9191f 100644
--- a/lib/libzpool/common/sys/zfs_context.h
+++ b/lib/libzpool/common/sys/zfs_context.h
@@ -542,7 +542,7 @@ extern void kernel_init(int);
extern void kernel_fini(void);
struct spa;
-extern void nicenum(uint64_t num, char *buf);
+extern void nicenum(uint64_t num, char *buf, size_t);
extern void show_pool_stats(struct spa *);
extern int set_global_var(char *arg);
diff --git a/lib/libzpool/common/util.c b/lib/libzpool/common/util.c
index e929aa564544..363940677c19 100644
--- a/lib/libzpool/common/util.c
+++ b/lib/libzpool/common/util.c
@@ -38,33 +38,6 @@
* Routines needed by more than one client of libzpool.
*/
-void
-nicenum(uint64_t num, char *buf)
-{
- uint64_t n = num;
- int index = 0;
- char u;
-
- while (n >= 1024) {
- n = (n + (1024 / 2)) / 1024; /* Round up or down */
- index++;
- }
-
- u = " KMGTPE"[index];
-
- if (index == 0) {
- (void) sprintf(buf, "%llu", (u_longlong_t)n);
- } else if (n < 10 && (num & (num - 1)) != 0) {
- (void) sprintf(buf, "%.2f%c",
- (double)num / (1ULL << 10 * index), u);
- } else if (n < 100 && (num & (num - 1)) != 0) {
- (void) sprintf(buf, "%.1f%c",
- (double)num / (1ULL << 10 * index), u);
- } else {
- (void) sprintf(buf, "%llu%c", (u_longlong_t)n, u);
- }
-}
-
static void
show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent)
{
@@ -97,15 +70,17 @@ show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent)
sec = MAX(1, vs->vs_timestamp / NANOSEC);
- nicenum(vs->vs_alloc, used);
- nicenum(vs->vs_space - vs->vs_alloc, avail);
- nicenum(vs->vs_ops[ZIO_TYPE_READ] / sec, rops);
- nicenum(vs->vs_ops[ZIO_TYPE_WRITE] / sec, wops);
- nicenum(vs->vs_bytes[ZIO_TYPE_READ] / sec, rbytes);
- nicenum(vs->vs_bytes[ZIO_TYPE_WRITE] / sec, wbytes);
- nicenum(vs->vs_read_errors, rerr);
- nicenum(vs->vs_write_errors, werr);
- nicenum(vs->vs_checksum_errors, cerr);
+ nicenum(vs->vs_alloc, used, sizeof (used));
+ nicenum(vs->vs_space - vs->vs_alloc, avail, sizeof (avail));
+ nicenum(vs->vs_ops[ZIO_TYPE_READ] / sec, rops, sizeof (rops));
+ nicenum(vs->vs_ops[ZIO_TYPE_WRITE] / sec, wops, sizeof (wops));
+ nicenum(vs->vs_bytes[ZIO_TYPE_READ] / sec, rbytes,
+ sizeof (rbytes));
+ nicenum(vs->vs_bytes[ZIO_TYPE_WRITE] / sec, wbytes,
+ sizeof (wbytes));
+ nicenum(vs->vs_read_errors, rerr, sizeof (rerr));
+ nicenum(vs->vs_write_errors, werr, sizeof (werr));
+ nicenum(vs->vs_checksum_errors, cerr, sizeof (cerr));
(void) printf("%*s%s%*s%*s%*s %5s %5s %5s %5s %5s %5s %5s\n",
indent, "",