xref: /titanic_41/usr/src/cmd/lvm/metassist/common/volume_string.c (revision ed5289f91b9bf164dccd6c75398362be77a4478d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "volume_string.h"
30 
31 #include <ctype.h>
32 #include <errno.h>
33 #include <libintl.h>
34 #include <math.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include "volume_error.h"
40 #include "volume_output.h"
41 
42 /*
43  * ******************************************************************
44  *
45  * Function prototypes
46  *
47  * ******************************************************************
48  */
49 
50 static void *append_to_pointer_array(void **array, void *pointer);
51 
52 /*
53  * ******************************************************************
54  *
55  * Data
56  *
57  * ******************************************************************
58  */
59 
60 /* All-inclusive valid size units */
61 units_t universal_units[] = {
62 	{"BLOCKS", BYTES_PER_BLOCK},
63 	{"KB", BYTES_PER_KILOBYTE},
64 	{"MB", BYTES_PER_MEGABYTE},
65 	{"GB", BYTES_PER_GIGABYTE},
66 	{"TB", BYTES_PER_TERABYTE},
67 	{NULL, 0}
68 };
69 
70 /*
71  * ******************************************************************
72  *
73  * External functions
74  *
75  * ******************************************************************
76  */
77 
78 /*
79  * Concatenates a list of strings.  The result must be free()d.
80  *
81  * @param       numargs
82  *              The number of strings to concatenate.
83  *
84  * @param       ...
85  *              The strings (type char *) to concatenate.
86  *
87  * @return      the concatenated string
88  *              if succesful
89  *
90  * @return      NULL
91  *              if memory could not be allocated
92  */
93 char *
94 stralloccat(
95 	int numargs,
96 	...)
97 {
98 	va_list vl;
99 	int i;
100 	int len = 1;
101 	char *cat;
102 
103 	/* Determine length of concatenated string */
104 	va_start(vl, numargs);
105 	for (i = 0; i < numargs; i++) {
106 	    char *str = va_arg(vl, char *);
107 	    if (str != NULL) {
108 		len += strlen(str);
109 	    }
110 	}
111 	va_end(vl);
112 
113 	/* Allocate memory for concatenation plus a trailing NULL */
114 	cat = (char *)calloc(1, len * sizeof (char));
115 
116 	if (cat == NULL) {
117 	    return (NULL);
118 	}
119 
120 	/* Concatenate strings */
121 	va_start(vl, numargs);
122 	for (i = 0; i < numargs; i++) {
123 	    char *str = va_arg(vl, char *);
124 	    if (str != NULL) {
125 		strcat(cat, str);
126 	    }
127 	}
128 	va_end(vl);
129 
130 	return (cat);
131 }
132 
133 /*
134  * Convert the given string to a uint16_t, verifying that the value
135  * does not exceed the lower or upper bounds of a uint16_t.
136  *
137  * @param       str
138  *              the string to convert
139  *
140  * @param       num
141  *              the addr of the uint16_t
142  *
143  * @return      0
144  *              if the given string was converted to a uint16_t
145  *
146  * @return      -1
147  *              if the string could could not be converted to a number
148  *
149  * @return      -2
150  *              if the converted number exceeds the lower or upper
151  *              bounds of a uint16_t
152  */
153 int
154 str_to_uint16(
155 	char *str,
156 	uint16_t *num)
157 {
158 	long long lnum;
159 	int error = 0;
160 
161 	/* Convert string to long long */
162 	if (sscanf(str, "%lld", &lnum) != 1) {
163 	    error = -1;
164 	} else {
165 
166 		/*
167 		 * Verify that the long long value does not exceed the
168 		 * lower or upper bounds of a uint16_t
169 		 */
170 
171 	    /* Maximum value of uint16_t */
172 	    uint16_t max = (uint16_t)~0ULL;
173 
174 	    if (lnum < 0 || lnum > max) {
175 		error = -2;
176 	    } else {
177 		*num = lnum;
178 	    }
179 	}
180 
181 	return (error);
182 }
183 
184 /*
185  * Converts the given long long into a string.  This string must be
186  * freed.
187  *
188  * @param       num
189  *              the long long to convert
190  *
191  * @param       str
192  *              the addr of the string
193  *
194  * @return      0
195  *              if successful
196  *
197  * @return      ENOMEM
198  *              if the physical limits of the system are exceeded by
199  *              size bytes of memory which cannot be allocated
200  *
201  * @return      EAGAIN
202  *              if there is not enough memory available to allocate
203  *              size bytes of memory
204  */
205 int
206 ll_to_str(
207 	long long num,
208 	char **str)
209 {
210 	int error = 0;
211 
212 	/* Allocate memory for the string */
213 	if ((*str = calloc(1, LONG_LONG_STR_SIZE * sizeof (char))) == NULL) {
214 	    error = errno;
215 	} else {
216 	    /* Convert the integer to a string */
217 	    snprintf(*str, LONG_LONG_STR_SIZE, "%lld", num);
218 	}
219 
220 	return (error);
221 }
222 
223 /*
224  * Convert a size specification to bytes.
225  *
226  * @param       str
227  *              a size specification strings of the form
228  *              <value><units>, where valid <units> are specified by
229  *              the units argument and <value> is the (floating-point)
230  *              multiplier of the units
231  *
232  * @param       bytes
233  *              RETURN: the result of converting the given size string
234  *              to bytes
235  *
236  * @return      0
237  *              if successful
238  *
239  * @return      non-zero
240  *              if an error occurred.  Use get_error_string() to
241  *              retrieve the associated error message.
242  */
243 int
244 sizestr_to_bytes(
245 	char *str,
246 	uint64_t *bytes,
247 	units_t units[])
248 {
249 	char *unit_str;
250 	long double d;
251 	int error = 0;
252 	int i;
253 
254 	/* Convert <value> string to double */
255 	if ((d = strtod(str, &unit_str)) == 0) {
256 	    volume_set_error(gettext("invalid size string: %s"), str);
257 	    error = -1;
258 	} else {
259 
260 	    /* Trim leading white space */
261 	    while (isspace(*unit_str) != 0) {
262 		++unit_str;
263 	    }
264 
265 	    /* Convert to bytes based on <units> */
266 	    for (i = 0; units[i].unit_str != NULL; i++) {
267 		if (strcasecmp(unit_str, units[i].unit_str) == 0) {
268 		    d *= units[i].bytes_per_unit;
269 		    break;
270 		}
271 	    }
272 
273 	    /* Was a valid unit string found? */
274 	    if (units[i].unit_str == NULL) {
275 		volume_set_error(
276 		    gettext("missing or invalid units indicator in size: %s"),
277 		    str);
278 		error = -1;
279 	    }
280 	}
281 
282 	if (error) {
283 	    *bytes = 0;
284 	} else {
285 	    *bytes = (uint64_t)d;
286 	    oprintf(OUTPUT_DEBUG,
287 		gettext("converted \"%s\" to %llu bytes\n"), str, *bytes);
288 	}
289 
290 	return (error);
291 }
292 
293 /*
294  * Convert bytes to a size specification string.
295  *
296  * @param       bytes
297  *              the number of bytes
298  *
299  * @param       str
300  *              RETURN: a size specification strings of the form
301  *              <value><units>, where valid <units> are specified by
302  *              the units argument and <value> is the (floating-point)
303  *              multiplier of the units.  This string must be freed.
304  *
305  * @return      0
306  *              if successful
307  *
308  * @return      non-zero
309  *              if an error occurred.  Use get_error_string() to
310  *              retrieve the associated error message.
311  */
312 int
313 bytes_to_sizestr(
314 	uint64_t bytes,
315 	char **str,
316 	units_t units[],
317 	boolean_t round)
318 {
319 	int i, len, error = 0;
320 	double value;
321 	const char *format;
322 	units_t use_units = units[0];
323 
324 	/* Determine the units to use */
325 	for (i = 0; units[i].unit_str != NULL; i++) {
326 	    if (bytes >= units[i].bytes_per_unit) {
327 		use_units = units[i];
328 	    }
329 	}
330 
331 	value = ((long double)bytes / use_units.bytes_per_unit);
332 
333 	/* Length of string plus trailing NULL */
334 	len = LONG_LONG_STR_SIZE + strlen(use_units.unit_str) + 1;
335 
336 	if (round) {
337 	    value = floor(value + 0.5F);
338 	    format = "%.0f%s";
339 	} else {
340 	    format = "%.2f%s";
341 	}
342 
343 	/* Append units to string */
344 	*str = calloc(1, len * sizeof (char));
345 	if (*str == NULL) {
346 	    error = errno;
347 	} else {
348 	    snprintf(*str, len, format, value, use_units.unit_str);
349 	}
350 
351 	return (error);
352 }
353 
354 /*
355  * Appends a copy of the given string to the given string array,
356  * ensuring that the last element in the array is NULL.  This array
357  * must be freed via free_string_array.
358  *
359  * Note when an error occurs and NULL is returned, array is not freed.
360  * Subsequently callers should save a pointer to the original array
361  * until success is verified.
362  *
363  * @param       array
364  *              the array to append to, or NULL to create a new array
365  *
366  * @param       str
367  *              the string to copy and add to the array
368  *
369  * @return      a pointer to the realloc'd (and possibly moved) array
370  *              if succesful
371  *
372  * @return      NULL
373  *              if unsuccesful
374  */
375 char **
376 append_to_string_array(
377 	char **array,
378 	char *str)
379 {
380 	char *copy = strdup(str);
381 
382 	if (copy == NULL) {
383 	    return (NULL);
384 	}
385 
386 	return ((char **)append_to_pointer_array((void **)array, copy));
387 }
388 
389 /*
390  * Frees each element of the given string array, then frees the array
391  * itself.
392  *
393  * @param       array
394  *              a NULL-terminated string array
395  */
396 void
397 free_string_array(
398 	char **array)
399 {
400 	int i;
401 
402 	/* Free each available element */
403 	for (i = 0; array[i] != NULL; i++) {
404 	    free(array[i]);
405 	}
406 
407 	/* Free the array itself */
408 	free((void *)array);
409 }
410 
411 /*
412  * ******************************************************************
413  *
414  * Static functions
415  *
416  * ******************************************************************
417  */
418 
419 /*
420  * Appends the given pointer to the given pointer array, ensuring that
421  * the last element in the array is NULL.
422  *
423  * Note when an error occurs and NULL is returned, array is not freed.
424  * Subsequently callers should save a pointer to the original array
425  * until success is verified.
426  *
427  * @param       array
428  *              the array to append to, or NULL to create a new array
429  *
430  * @param       pointer
431  *              the pointer to add to the array
432  *
433  * @return      a pointer to the realloc'd (and possibly moved) array
434  *              if succesful
435  *
436  * @return      NULL
437  *              if unsuccesful
438  */
439 static void *
440 append_to_pointer_array(
441 	void **array,
442 	void *pointer)
443 {
444 	void **newarray = NULL;
445 	int i = 0;
446 
447 	if (array != NULL) {
448 	    /* Count the elements currently in the array */
449 	    for (i = 0; array[i] != NULL; ++i);
450 	}
451 
452 	/* realloc, adding a slot for the new pointer */
453 	newarray = (void **)realloc(array, (i + 2) * sizeof (*array));
454 
455 	if (newarray != NULL) {
456 	    /* Append pointer and terminal NULL */
457 	    newarray[i] = pointer;
458 	    newarray[i+1] = NULL;
459 	}
460 
461 	return (newarray);
462 }
463