dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / prctl / utils.c
blob20b84befd06d84aedcd35b38c1e74831b66399d3
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/param.h>
27 #include <libintl.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <strings.h>
34 #include <sys/types.h>
35 #include <limits.h>
36 #include "utils.h"
38 static char PNAME_FMT[] = "%s: ";
39 static char ERRNO_FMT[] = ": %s\n";
40 static char EOL_FMT[] = "\n";
42 static char *pname;
44 char *
45 setpname(char *arg0)
47 char *p = strrchr(arg0, '/');
49 if (p == NULL)
50 p = arg0;
51 else
52 p++;
53 pname = p;
54 return (pname);
57 /*PRINTFLIKE1*/
58 void
59 warn(const char *format, ...)
61 int err = errno;
62 va_list alist;
63 if (pname != NULL)
64 (void) fprintf(stderr, gettext(PNAME_FMT), pname);
65 va_start(alist, format);
66 (void) vfprintf(stderr, format, alist);
67 va_end(alist);
68 if (strchr(format, '\n') == NULL)
69 if (err)
70 (void) fprintf(stderr,
71 gettext(ERRNO_FMT), strerror(err));
72 else
73 (void) fprintf(stderr, gettext(EOL_FMT));
78 static char *__metric_modifiers[] = { "K", "M", "G", "T", "P", "E", NULL };
79 static uint64_t __metric_scales[] = {
80 1000LLU,
81 1000LLU * 1000,
82 1000LLU * 1000 * 1000,
83 1000LLU * 1000 * 1000 * 1000,
84 1000LLU * 1000 * 1000 * 1000 * 1000,
85 1000LLU * 1000 * 1000 * 1000 * 1000 * 1000
87 static scale_t __metric_scale = { __metric_modifiers, __metric_scales };
89 static char *__binary_modifiers[] = {"K", "M", "G", "T", "P", "E", NULL};
90 static uint64_t __binary_scales[] = {
91 1024LLU,
92 1024LLU * 1024,
93 1024LLU * 1024 * 1024,
94 1024LLU * 1024 * 1024 * 1024,
95 1024LLU * 1024 * 1024 * 1024 * 1024,
96 1024LLU * 1024 * 1024 * 1024 * 1024 * 1024
98 static scale_t __binary_scale = { __binary_modifiers, __binary_scales };
100 scale_t *scale_metric = &__metric_scale;
101 scale_t *scale_binary = &__binary_scale;
104 scaledtouint64(char *scaledin,
105 uint64_t *uint64out,
106 int *widthout, char **modifierout, char **unitout,
107 scale_t *scale, char *unit, int flags) {
109 double result;
110 double value;
111 int index = 0;
112 uint64_t multiplier = 1;
113 char string[SCALED_STRLEN];
114 char *endptr;
115 int cmp;
116 int hasmodifier = 0;
117 char **modifiers = scale->modifers;
118 uint64_t *scales = scale->scales;
120 if (modifierout)
121 *modifierout = NULL;
122 if (unitout)
123 *unitout = NULL;
126 * first check for hex value, which cannot be scaled, as
127 * hex letters cannot be disserned from modifier or unit letters
129 if ((strncmp("0x", scaledin, 2) == 0) ||
130 (strncmp("0X", scaledin, 2) == 0)) {
132 /* unit cannot be required on hex values */
133 if ((unit && *unit != '\0') &&
134 !(flags & SCALED_UNIT_OPTIONAL_FLAG))
135 return (SCALED_INVALID_UNIT);
137 errno = 0;
138 *uint64out = strtoull(scaledin, &endptr, 16);
139 if (errno) {
140 if (errno == ERANGE)
141 return (SCALED_OVERFLOW);
142 else
143 return (SCALED_INVALID_NUMBER);
145 if (*endptr != '\0')
146 return (SCALED_INVALID_NUMBER);
148 /* compute width of decimal equivalent */
149 if (widthout) {
150 (void) snprintf(
151 string, SCALED_STRLEN, "%llu", *uint64out);
152 *widthout = strlen(string);
154 return (0);
157 /* scan out numeric value */
158 errno = 0;
159 value = strtod(scaledin, &endptr);
160 if (errno) {
161 if (errno == ERANGE)
162 return (SCALED_OVERFLOW);
163 else
164 return (SCALED_INVALID_NUMBER);
167 if (endptr == scaledin)
168 return (SCALED_INVALID_NUMBER);
170 /* no negative values */
171 if (strchr(scaledin, '-'))
172 return (SCALED_INVALID_NUMBER);
173 if (value < 0.0)
174 return (SCALED_INVALID_NUMBER);
177 /* compute width of number string */
178 if (widthout)
179 *widthout = (int)(endptr - scaledin);
181 /* check possible modifier */
182 if (*endptr != '\0') {
183 index = 0;
184 while (modifiers[index] != NULL) {
185 if (flags & SCALED_MODIFIER_CASE_INSENSITIVE_FLAG)
186 cmp = strncasecmp(modifiers[index], endptr,
187 strlen(modifiers[index]));
188 else
189 cmp = strncmp(modifiers[index], endptr,
190 strlen(modifiers[index]));
192 if (cmp == 0) {
193 if (modifierout)
194 *modifierout = modifiers[index];
195 endptr += strlen(modifiers[index]);
196 multiplier = scales[index];
197 result = value * multiplier;
198 if (result > UINT64_MAX)
199 return (SCALED_OVERFLOW);
201 *uint64out = (uint64_t)result;
202 hasmodifier = 1;
203 break;
205 index++;
208 /* if there is no modifier, value must be an integer */
209 if (!hasmodifier) {
210 errno = 0;
211 *uint64out = strtoull(scaledin, &endptr, 0);
212 if (errno) {
213 if (errno == ERANGE)
214 return (SCALED_OVERFLOW);
215 else
216 return (SCALED_INVALID_NUMBER);
218 if (endptr == scaledin)
219 return (SCALED_INVALID_NUMBER);
222 /* if unit is present when no unit is allowed, fail */
223 if ((unit == NULL || *unit == '\0') && (*endptr != '\0'))
224 return (SCALED_INVALID_UNIT);
226 /* check for missing unit when unit is required */
227 if ((unit && *unit != '\0') &&
228 !(flags & SCALED_UNIT_OPTIONAL_FLAG) &&
229 (*endptr == '\0'))
230 return (SCALED_INVALID_UNIT);
232 /* validate unit */
233 if (unit && *unit != '\0') {
235 /* allow for missing unit if it is optional */
236 if ((flags & SCALED_UNIT_OPTIONAL_FLAG) &&
237 (*endptr == '\0'))
238 return (0);
240 if (flags & SCALED_UNIT_CASE_INSENSITIVE_FLAG)
241 cmp = strncasecmp(unit, endptr, strlen(unit));
242 else
243 cmp = strncmp(unit, endptr, strlen(unit));
245 if (cmp != 0)
246 return (SCALED_INVALID_UNIT);
248 if (*(endptr + strlen(unit)) != '\0')
249 return (SCALED_INVALID_UNIT);
251 if (unitout)
252 *unitout = unit;
254 return (0);
259 uint64toscaled(uint64_t uint64in, int widthin, char *maxmodifierin,
260 char *scaledout, int *widthout, char **modifierout,
261 scale_t *scale, char *unit, int flags) {
263 int index = 0;
264 int count;
265 int width;
266 int decimals = 0;
267 char string[SCALED_STRLEN];
268 double value;
269 char **modifiers = scale->modifers;
270 uint64_t *scales = scale->scales;
272 /* don't scale if there is no reason to */
273 if (uint64in < scales[0] || maxmodifierin == NULL) {
274 if (flags & SCALED_PAD_WIDTH_FLAG)
275 width = widthin;
276 else
277 width = 0;
279 (void) snprintf(string, SCALED_STRLEN, "%%%dllu", width);
280 /* LINTED */
281 count = snprintf(scaledout, SCALED_STRLEN, string, uint64in);
282 if (unit && *unit != '\0')
283 (void) strcat(scaledout, unit);
285 if (widthout)
286 *widthout = count;
288 if (modifierout)
289 *modifierout = NULL;
291 return (0);
294 for (index = 0; modifiers[index + 1] != NULL; index++) {
296 if (uint64in >= scales[index] &&
297 uint64in < scales[index + 1])
298 break;
300 if ((strncmp(modifiers[index], maxmodifierin,
301 strlen(modifiers[index])) == 0) &&
302 (strlen(modifiers[index]) == strlen(maxmodifierin)))
303 break;
307 value = ((double)(uint64in)) / scales[index];
308 if (modifierout)
309 *modifierout = modifiers[index];
311 count = snprintf(string, SCALED_STRLEN, "%0.0lf", value);
312 while (count < widthin) {
313 decimals++;
314 (void) snprintf(string, SCALED_STRLEN, "%%0.%dlf", decimals);
315 /* LINTED */
316 count = snprintf(scaledout, SCALED_STRLEN, string, value);
318 /* reduce decimal places if we've overshot the desired width */
319 if (count > widthin) {
320 decimals--;
321 break;
325 if (flags & SCALED_PAD_WIDTH_FLAG)
326 width = widthin;
327 else
328 width = 0;
330 (void) snprintf(string, SCALED_STRLEN, "%%%d.%dlf", width, decimals);
331 /* LINTED */
332 count = snprintf(scaledout, SCALED_STRLEN, string, value);
334 (void) strcat(scaledout, modifiers[index]);
336 if (unit && *unit != '\0')
337 (void) strcat(scaledout, unit);
339 if (widthout)
340 *widthout = count;
342 return (0);
346 scaledtoscaled(char *scaledin, int widthin, char *maxmodifierin,
347 char *scaledout, int *widthout, char **modifierout,
348 scale_t *scale, char *unit, int flags) {
350 int ret;
351 uint64_t val;
353 ret = scaledtouint64(scaledin, &val, NULL, NULL, NULL,
354 scale, unit, flags);
355 if (ret)
356 return (ret);
358 ret = uint64toscaled(val, widthin, maxmodifierin,
359 scaledout, widthout, modifierout,
360 scale, unit, flags);
362 return (ret);
366 scaledeqscaled(char *scaled1, char *scaled2,
367 scale_t *scale, char *unit, int flags) {
369 int ret;
370 uint64_t uint64;
371 char *modifier1;
372 char *modifier2;
373 char *modifier = NULL;
374 int i;
375 int width;
376 int width1;
377 int width2;
378 char scaledA[SCALED_STRLEN];
379 char scaledB[SCALED_STRLEN];
380 char **modifiers = scale->modifers;
383 * remove padding flag, so strings to compare will not have
384 * whitespace
386 flags = flags & (~SCALED_PAD_WIDTH_FLAG);
388 /* determine each number's width and modifier */
389 ret = scaledtouint64(scaled1, &uint64, &width1, &modifier1, NULL,
390 scale, unit, flags);
391 if (ret)
392 return (0);
394 ret = scaledtouint64(scaled2, &uint64, &width2, &modifier2, NULL,
395 scale, unit, flags);
396 if (ret)
397 return (0);
400 * determine the width and modifier to use for comparison.
401 * Use widest width and smallest modifier.
402 * Rescale to new width and modifier
405 if (modifier1 == NULL || modifier2 == NULL)
406 modifier = NULL;
407 else {
408 for (i = 0; modifiers[i] != NULL; i++) {
410 if (strcmp(modifier1, modifiers[i]) == 0) {
411 modifier = modifiers[i];
412 break;
414 if (strcmp(modifier2, modifiers[i]) == 0) {
415 modifier = modifiers[i];
416 break;
420 width = 0;
421 if (width1 > width)
422 width = width1;
423 if (width2 > width)
424 width = width2;
427 * Convert first number to width and modifier.
428 * This is done for the following reasons:
429 * 1. In case first number is hecadecimal. This will convert
430 * it to decimal
431 * 2. In case the first number has < the minimum number of
432 * columns.
433 * 3. The first number is missing an optional unit string.
434 * 4. Fix casing of modifier and unit.
437 ret = scaledtoscaled(scaled1, width, modifier,
438 scaledA, NULL, NULL, scale, unit, flags);
439 if (ret)
440 return (0);
442 /* convert second number to width and modifier matching first number */
443 ret = scaledtoscaled(scaled2, width, modifier,
444 scaledB, NULL, NULL, scale, unit, flags);
445 if (ret)
446 return (0);
448 /* numbers are equal if strings match */
449 return ((strncmp(scaledA, scaledB, strlen(scaledA)) == 0) &&
450 (strlen(scaledA) == strlen(scaledB)));
455 scaledequint64(char *scaled, uint64_t uint64, int minwidth,
456 scale_t *scale, char *unit, int flags) {
458 int ret;
459 uint64_t tmpuint64;
460 char *modifier;
461 int width;
463 char scaledA[SCALED_STRLEN];
464 char scaledB[SCALED_STRLEN];
466 /* determine for number's width and modifier */
467 ret = scaledtouint64(scaled, &tmpuint64, &width, &modifier, NULL,
468 scale, unit, flags);
469 if (ret)
470 return (0);
472 if (width < minwidth)
473 width = minwidth;
476 * Convert first number to width and modifier.
477 * This is done for the following reasons:
478 * 1. In case first number is hecadecimal. This will convert
479 * it to decimal
480 * 2. In case the first number has < the minimum number of
481 * columns.
482 * 3. The first number is missing an optional unit string.
483 * 4. Fix casing of modifier and unit.
486 ret = scaledtoscaled(scaled, width, modifier,
487 scaledA, NULL, NULL, scale, unit, flags);
488 if (ret)
489 return (0);
491 /* convert second number to width and modifier matching first number */
492 ret = uint64toscaled(uint64, width, modifier,
493 scaledB, NULL, NULL, scale, unit, flags);
494 if (ret)
495 return (0);
497 /* numbers are equal if strings match */
498 return ((strncmp(scaledA, scaledB, strlen(scaledA)) == 0) &&
499 (strlen(scaledA) == strlen(scaledB)));