summaryrefslogtreecommitdiff
path: root/usr/src/cmd/prctl/utils.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/prctl/utils.c
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/prctl/utils.c')
-rw-r--r--usr/src/cmd/prctl/utils.c503
1 files changed, 503 insertions, 0 deletions
diff --git a/usr/src/cmd/prctl/utils.c b/usr/src/cmd/prctl/utils.c
new file mode 100644
index 0000000000..ed26af704e
--- /dev/null
+++ b/usr/src/cmd/prctl/utils.c
@@ -0,0 +1,503 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <libintl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <limits.h>
+#include "utils.h"
+
+static char PNAME_FMT[] = "%s: ";
+static char ERRNO_FMT[] = ": %s\n";
+static char EOL_FMT[] = "\n";
+
+static char *pname;
+
+char *
+setprogname(char *arg0)
+{
+ char *p = strrchr(arg0, '/');
+
+ if (p == NULL)
+ p = arg0;
+ else
+ p++;
+ pname = p;
+ return (pname);
+}
+
+/*PRINTFLIKE1*/
+void
+warn(char *format, ...)
+{
+ int err = errno;
+ va_list alist;
+ if (pname != NULL)
+ (void) fprintf(stderr, gettext(PNAME_FMT), pname);
+ va_start(alist, format);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+ if (strchr(format, '\n') == NULL)
+ if (err)
+ (void) fprintf(stderr,
+ gettext(ERRNO_FMT), strerror(err));
+ else
+ (void) fprintf(stderr, gettext(EOL_FMT));
+
+
+}
+
+static char *__metric_modifiers[] = { "K", "M", "G", "T", "P", "E", NULL };
+static uint64_t __metric_scales[] = {
+ 1000LLU,
+ 1000LLU * 1000,
+ 1000LLU * 1000 * 1000,
+ 1000LLU * 1000 * 1000 * 1000,
+ 1000LLU * 1000 * 1000 * 1000 * 1000,
+ 1000LLU * 1000 * 1000 * 1000 * 1000 * 1000
+};
+static scale_t __metric_scale = { __metric_modifiers, __metric_scales };
+
+static char *__binary_modifiers[] = {"K", "M", "G", "T", "P", "E", NULL};
+static uint64_t __binary_scales[] = {
+ 1024LLU,
+ 1024LLU * 1024,
+ 1024LLU * 1024 * 1024,
+ 1024LLU * 1024 * 1024 * 1024,
+ 1024LLU * 1024 * 1024 * 1024 * 1024,
+ 1024LLU * 1024 * 1024 * 1024 * 1024 * 1024
+};
+static scale_t __binary_scale = { __binary_modifiers, __binary_scales };
+
+scale_t *scale_metric = &__metric_scale;
+scale_t *scale_binary = &__binary_scale;
+
+int
+scaledtouint64(char *scaledin,
+ uint64_t *uint64out,
+ int *widthout, char **modifierout, char **unitout,
+ scale_t *scale, char *unit, int flags) {
+
+ double result;
+ double value;
+ int index = 0;
+ uint64_t multiplier = 1;
+ char string[SCALED_STRLEN];
+ char *endptr;
+ int cmp;
+ int hasmodifier = 0;
+ char **modifiers = scale->modifers;
+ uint64_t *scales = scale->scales;
+
+ if (modifierout)
+ *modifierout = NULL;
+ if (unitout)
+ *unitout = NULL;
+
+ /*
+ * first check for hex value, which cannot be scaled, as
+ * hex letters cannot be disserned from modifier or unit letters
+ */
+ if ((strncmp("0x", scaledin, 2) == 0) ||
+ (strncmp("0X", scaledin, 2) == 0)) {
+
+ /* unit cannot be required on hex values */
+ if ((unit && *unit != '\0') &&
+ !(flags & SCALED_UNIT_OPTIONAL_FLAG))
+ return (SCALED_INVALID_UNIT);
+
+ errno = 0;
+ *uint64out = strtoull(scaledin, &endptr, 16);
+ if (errno) {
+ if (errno == ERANGE)
+ return (SCALED_OVERFLOW);
+ else
+ return (SCALED_INVALID_NUMBER);
+ }
+ if (*endptr != '\0')
+ return (SCALED_INVALID_NUMBER);
+
+ /* compute width of decimal equivalent */
+ if (widthout) {
+ (void) snprintf(
+ string, SCALED_STRLEN, "%llu", *uint64out);
+ *widthout = strlen(string);
+ }
+ return (0);
+ }
+
+ /* scan out numeric value */
+ errno = 0;
+ value = strtod(scaledin, &endptr);
+ if (errno) {
+ if (errno == ERANGE)
+ return (SCALED_OVERFLOW);
+ else
+ return (SCALED_INVALID_NUMBER);
+
+ }
+ if (endptr == scaledin)
+ return (SCALED_INVALID_NUMBER);
+
+ /* no negative values */
+ if (strchr(scaledin, '-'))
+ return (SCALED_INVALID_NUMBER);
+ if (value < 0.0)
+ return (SCALED_INVALID_NUMBER);
+
+
+ /* compute width of number string */
+ if (widthout)
+ *widthout = (int)(endptr - scaledin);
+
+ /* check possible modifier */
+ if (*endptr != '\0') {
+ index = 0;
+ while (modifiers[index] != NULL) {
+ if (flags & SCALED_MODIFIER_CASE_INSENSITIVE_FLAG)
+ cmp = strncasecmp(modifiers[index], endptr,
+ strlen(modifiers[index]));
+ else
+ cmp = strncmp(modifiers[index], endptr,
+ strlen(modifiers[index]));
+
+ if (cmp == 0) {
+ if (modifierout)
+ *modifierout = modifiers[index];
+ endptr += strlen(modifiers[index]);
+ multiplier = scales[index];
+ result = value * multiplier;
+ if (result > UINT64_MAX)
+ return (SCALED_OVERFLOW);
+
+ *uint64out = (uint64_t)result;
+ hasmodifier = 1;
+ break;
+ }
+ index++;
+ }
+ }
+ /* if there is no modifier, value must be an integer */
+ if (!hasmodifier) {
+ errno = 0;
+ *uint64out = strtoull(scaledin, &endptr, 0);
+ if (errno) {
+ if (errno == ERANGE)
+ return (SCALED_OVERFLOW);
+ else
+ return (SCALED_INVALID_NUMBER);
+ }
+ if (endptr == scaledin)
+ return (SCALED_INVALID_NUMBER);
+ }
+
+ /* if unit is present when no unit is allowed, fail */
+ if ((unit == NULL || *unit == '\0') && (*endptr != '\0'))
+ return (SCALED_INVALID_UNIT);
+
+ /* check for missing unit when unit is required */
+ if ((unit && *unit != '\0') &&
+ !(flags & SCALED_UNIT_OPTIONAL_FLAG) &&
+ (*endptr == '\0'))
+ return (SCALED_INVALID_UNIT);
+
+ /* validate unit */
+ if (unit && *unit != '\0') {
+
+ /* allow for missing unit if it is optional */
+ if ((flags & SCALED_UNIT_OPTIONAL_FLAG) &&
+ (*endptr == '\0'))
+ return (0);
+
+ if (flags & SCALED_UNIT_CASE_INSENSITIVE_FLAG)
+ cmp = strncasecmp(unit, endptr, strlen(unit));
+ else
+ cmp = strncmp(unit, endptr, strlen(unit));
+
+ if (cmp != 0)
+ return (SCALED_INVALID_UNIT);
+
+ if (*(endptr + strlen(unit)) != '\0')
+ return (SCALED_INVALID_UNIT);
+
+ if (unitout)
+ *unitout = unit;
+ }
+ return (0);
+}
+
+
+int
+uint64toscaled(uint64_t uint64in, int widthin, char *maxmodifierin,
+ char *scaledout, int *widthout, char **modifierout,
+ scale_t *scale, char *unit, int flags) {
+
+ int index = 0;
+ int count;
+ int width;
+ int decimals = 0;
+ char string[SCALED_STRLEN];
+ double value;
+ char **modifiers = scale->modifers;
+ uint64_t *scales = scale->scales;
+
+ /* don't scale if there is no reason to */
+ if (uint64in < scales[0] || maxmodifierin == NULL) {
+ if (flags & SCALED_PAD_WIDTH_FLAG)
+ width = widthin;
+ else
+ width = 0;
+
+ (void) snprintf(string, SCALED_STRLEN, "%%%dllu", width);
+ /* LINTED */
+ count = snprintf(scaledout, SCALED_STRLEN, string, uint64in);
+ if (unit && *unit != '\0')
+ (void) strcat(scaledout, unit);
+
+ if (widthout)
+ *widthout = count;
+
+ if (modifierout)
+ *modifierout = NULL;
+
+ return (0);
+ }
+
+ for (index = 0; modifiers[index + 1] != NULL; index++) {
+
+ if (uint64in >= scales[index] &&
+ uint64in < scales[index + 1])
+ break;
+
+ if ((strncmp(modifiers[index], maxmodifierin,
+ strlen(modifiers[index])) == 0) &&
+ (strlen(modifiers[index]) == strlen(maxmodifierin)))
+ break;
+
+ }
+
+ value = ((double)(uint64in)) / scales[index];
+ if (modifierout)
+ *modifierout = modifiers[index];
+
+ count = snprintf(string, SCALED_STRLEN, "%0.0lf", value);
+ while (count < widthin) {
+ decimals++;
+ (void) snprintf(string, SCALED_STRLEN, "%%0.%dlf", decimals);
+ /* LINTED */
+ count = snprintf(scaledout, SCALED_STRLEN, string, value);
+
+ /* reduce decimal places if we've overshot the desired width */
+ if (count > widthin) {
+ decimals--;
+ break;
+ }
+ }
+
+ if (flags & SCALED_PAD_WIDTH_FLAG)
+ width = widthin;
+ else
+ width = 0;
+
+ (void) snprintf(string, SCALED_STRLEN, "%%%d.%dlf", width, decimals);
+ /* LINTED */
+ count = snprintf(scaledout, SCALED_STRLEN, string, value);
+
+ (void) strcat(scaledout, modifiers[index]);
+
+ if (unit && *unit != '\0')
+ (void) strcat(scaledout, unit);
+
+ if (widthout)
+ *widthout = count;
+
+ return (0);
+}
+
+int
+scaledtoscaled(char *scaledin, int widthin, char *maxmodifierin,
+ char *scaledout, int *widthout, char **modifierout,
+ scale_t *scale, char *unit, int flags) {
+
+ int ret;
+ uint64_t val;
+
+ ret = scaledtouint64(scaledin, &val, NULL, NULL, NULL,
+ scale, unit, flags);
+ if (ret)
+ return (ret);
+
+ ret = uint64toscaled(val, widthin, maxmodifierin,
+ scaledout, widthout, modifierout,
+ scale, unit, flags);
+
+ return (ret);
+}
+
+int
+scaledeqscaled(char *scaled1, char *scaled2,
+ scale_t *scale, char *unit, int flags) {
+
+ int ret;
+ uint64_t uint64;
+ char *modifier1;
+ char *modifier2;
+ char *modifier = NULL;
+ int i;
+ int width;
+ int width1;
+ int width2;
+ char scaledA[SCALED_STRLEN];
+ char scaledB[SCALED_STRLEN];
+ char **modifiers = scale->modifers;
+
+ /*
+ * remove padding flag, so strings to compare will not have
+ * whitespace
+ */
+ flags = flags & (~SCALED_PAD_WIDTH_FLAG);
+
+ /* determine each number's width and modifier */
+ ret = scaledtouint64(scaled1, &uint64, &width1, &modifier1, NULL,
+ scale, unit, flags);
+ if (ret)
+ return (0);
+
+ ret = scaledtouint64(scaled2, &uint64, &width2, &modifier2, NULL,
+ scale, unit, flags);
+ if (ret)
+ return (0);
+
+ /*
+ * determine the width and modifier to use for comparison.
+ * Use widest width and smallest modifier.
+ * Rescale to new width and modifier
+ */
+
+ if (modifier1 == NULL || modifier2 == NULL)
+ modifier = NULL;
+ else {
+ for (i = 0; modifiers[i] != NULL; i++) {
+
+ if (strcmp(modifier1, modifiers[i]) == 0) {
+ modifier = modifiers[i];
+ break;
+ }
+ if (strcmp(modifier2, modifiers[i]) == 0) {
+ modifier = modifiers[i];
+ break;
+ }
+ }
+ }
+ width = 0;
+ if (width1 > width)
+ width = width1;
+ if (width2 > width)
+ width = width2;
+
+ /*
+ * Convert first number to width and modifier.
+ * This is done for the following reasons:
+ * 1. In case first number is hecadecimal. This will convert
+ * it to decimal
+ * 2. In case the first number has < the minimum number of
+ * columns.
+ * 3. The first number is missing an optional unit string.
+ * 4. Fix casing of modifier and unit.
+ */
+
+ ret = scaledtoscaled(scaled1, width, modifier,
+ scaledA, NULL, NULL, scale, unit, flags);
+ if (ret)
+ return (0);
+
+ /* convert second number to width and modifier matching first number */
+ ret = scaledtoscaled(scaled2, width, modifier,
+ scaledB, NULL, NULL, scale, unit, flags);
+ if (ret)
+ return (0);
+
+ /* numbers are equal if strings match */
+ return ((strncmp(scaledA, scaledB, strlen(scaledA)) == 0) &&
+ (strlen(scaledA) == strlen(scaledB)));
+
+}
+
+int
+scaledequint64(char *scaled, uint64_t uint64, int minwidth,
+ scale_t *scale, char *unit, int flags) {
+
+ int ret;
+ uint64_t tmpuint64;
+ char *modifier;
+ int width;
+
+ char scaledA[SCALED_STRLEN];
+ char scaledB[SCALED_STRLEN];
+
+ /* determine for number's width and modifier */
+ ret = scaledtouint64(scaled, &tmpuint64, &width, &modifier, NULL,
+ scale, unit, flags);
+ if (ret)
+ return (0);
+
+ if (width < minwidth)
+ width = minwidth;
+
+ /*
+ * Convert first number to width and modifier.
+ * This is done for the following reasons:
+ * 1. In case first number is hecadecimal. This will convert
+ * it to decimal
+ * 2. In case the first number has < the minimum number of
+ * columns.
+ * 3. The first number is missing an optional unit string.
+ * 4. Fix casing of modifier and unit.
+ */
+
+ ret = scaledtoscaled(scaled, width, modifier,
+ scaledA, NULL, NULL, scale, unit, flags);
+ if (ret)
+ return (0);
+
+ /* convert second number to width and modifier matching first number */
+ ret = uint64toscaled(uint64, width, modifier,
+ scaledB, NULL, NULL, scale, unit, flags);
+ if (ret)
+ return (0);
+
+ /* numbers are equal if strings match */
+ return ((strncmp(scaledA, scaledB, strlen(scaledA)) == 0) &&
+ (strlen(scaledA) == strlen(scaledB)));
+}