/* * 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 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include "volume_string.h" #include #include #include #include #include #include #include #include #include "volume_error.h" #include "volume_output.h" /* * ****************************************************************** * * Function prototypes * * ****************************************************************** */ static void *append_to_pointer_array(void **array, void *pointer); /* * ****************************************************************** * * Data * * ****************************************************************** */ /* All-inclusive valid size units */ units_t universal_units[] = { {"BLOCKS", BYTES_PER_BLOCK}, {"KB", BYTES_PER_KILOBYTE}, {"MB", BYTES_PER_MEGABYTE}, {"GB", BYTES_PER_GIGABYTE}, {"TB", BYTES_PER_TERABYTE}, {NULL, 0} }; /* * ****************************************************************** * * External functions * * ****************************************************************** */ /* * Concatenates a list of strings. The result must be free()d. * * @param numargs * The number of strings to concatenate. * * @param ... * The strings (type char *) to concatenate. * * @return the concatenated string * if succesful * * @return NULL * if memory could not be allocated */ char * stralloccat( int numargs, ...) { va_list vl; int i; int len = 1; char *cat; /* Determine length of concatenated string */ va_start(vl, numargs); for (i = 0; i < numargs; i++) { char *str = va_arg(vl, char *); if (str != NULL) { len += strlen(str); } } va_end(vl); /* Allocate memory for concatenation plus a trailing NULL */ cat = (char *)calloc(1, len * sizeof (char)); if (cat == NULL) { return (NULL); } /* Concatenate strings */ va_start(vl, numargs); for (i = 0; i < numargs; i++) { char *str = va_arg(vl, char *); if (str != NULL) { strcat(cat, str); } } va_end(vl); return (cat); } /* * Convert the given string to a uint16_t, verifying that the value * does not exceed the lower or upper bounds of a uint16_t. * * @param str * the string to convert * * @param num * the addr of the uint16_t * * @return 0 * if the given string was converted to a uint16_t * * @return -1 * if the string could could not be converted to a number * * @return -2 * if the converted number exceeds the lower or upper * bounds of a uint16_t */ int str_to_uint16( char *str, uint16_t *num) { long long lnum; int error = 0; /* Convert string to long long */ if (sscanf(str, "%lld", &lnum) != 1) { error = -1; } else { /* * Verify that the long long value does not exceed the * lower or upper bounds of a uint16_t */ /* Maximum value of uint16_t */ uint16_t max = (uint16_t)~0ULL; if (lnum < 0 || lnum > max) { error = -2; } else { *num = lnum; } } return (error); } /* * Converts the given long long into a string. This string must be * freed. * * @param num * the long long to convert * * @param str * the addr of the string * * @return 0 * if successful * * @return ENOMEM * if the physical limits of the system are exceeded by * size bytes of memory which cannot be allocated * * @return EAGAIN * if there is not enough memory available to allocate * size bytes of memory */ int ll_to_str( long long num, char **str) { int error = 0; /* Allocate memory for the string */ if ((*str = calloc(1, LONG_LONG_STR_SIZE * sizeof (char))) == NULL) { error = errno; } else { /* Convert the integer to a string */ snprintf(*str, LONG_LONG_STR_SIZE, "%lld", num); } return (error); } /* * Convert a size specification to bytes. * * @param str * a size specification strings of the form * , where valid are specified by * the units argument and is the (floating-point) * multiplier of the units * * @param bytes * RETURN: the result of converting the given size string * to bytes * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int sizestr_to_bytes( char *str, uint64_t *bytes, units_t units[]) { char *unit_str; long double d; int error = 0; int i; /* Convert string to double */ if ((d = strtod(str, &unit_str)) == 0) { volume_set_error(gettext("invalid size string: %s"), str); error = -1; } else { /* Trim leading white space */ while (isspace(*unit_str) != 0) { ++unit_str; } /* Convert to bytes based on */ for (i = 0; units[i].unit_str != NULL; i++) { if (strcasecmp(unit_str, units[i].unit_str) == 0) { d *= units[i].bytes_per_unit; break; } } /* Was a valid unit string found? */ if (units[i].unit_str == NULL) { volume_set_error( gettext("missing or invalid units indicator in size: %s"), str); error = -1; } } if (error) { *bytes = 0; } else { *bytes = (uint64_t)d; oprintf(OUTPUT_DEBUG, gettext("converted \"%s\" to %llu bytes\n"), str, *bytes); } return (error); } /* * Convert bytes to a size specification string. * * @param bytes * the number of bytes * * @param str * RETURN: a size specification strings of the form * , where valid are specified by * the units argument and is the (floating-point) * multiplier of the units. This string must be freed. * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int bytes_to_sizestr( uint64_t bytes, char **str, units_t units[], boolean_t round) { int i, len, error = 0; double value; const char *format; units_t use_units = units[0]; /* Determine the units to use */ for (i = 0; units[i].unit_str != NULL; i++) { if (bytes >= units[i].bytes_per_unit) { use_units = units[i]; } } value = ((long double)bytes / use_units.bytes_per_unit); /* Length of string plus trailing NULL */ len = LONG_LONG_STR_SIZE + strlen(use_units.unit_str) + 1; if (round) { value = floor(value + 0.5F); format = "%.0f%s"; } else { format = "%.2f%s"; } /* Append units to string */ *str = calloc(1, len * sizeof (char)); if (*str == NULL) { error = errno; } else { snprintf(*str, len, format, value, use_units.unit_str); } return (error); } /* * Appends a copy of the given string to the given string array, * ensuring that the last element in the array is NULL. This array * must be freed via free_string_array. * * Note when an error occurs and NULL is returned, array is not freed. * Subsequently callers should save a pointer to the original array * until success is verified. * * @param array * the array to append to, or NULL to create a new array * * @param str * the string to copy and add to the array * * @return a pointer to the realloc'd (and possibly moved) array * if succesful * * @return NULL * if unsuccesful */ char ** append_to_string_array( char **array, char *str) { char *copy = strdup(str); if (copy == NULL) { return (NULL); } return ((char **)append_to_pointer_array((void **)array, copy)); } /* * Frees each element of the given string array, then frees the array * itself. * * @param array * a NULL-terminated string array */ void free_string_array( char **array) { int i; /* Free each available element */ for (i = 0; array[i] != NULL; i++) { free(array[i]); } /* Free the array itself */ free((void *)array); } /* * ****************************************************************** * * Static functions * * ****************************************************************** */ /* * Appends the given pointer to the given pointer array, ensuring that * the last element in the array is NULL. * * Note when an error occurs and NULL is returned, array is not freed. * Subsequently callers should save a pointer to the original array * until success is verified. * * @param array * the array to append to, or NULL to create a new array * * @param pointer * the pointer to add to the array * * @return a pointer to the realloc'd (and possibly moved) array * if succesful * * @return NULL * if unsuccesful */ static void * append_to_pointer_array( void **array, void *pointer) { void **newarray = NULL; int i = 0; if (array != NULL) { /* Count the elements currently in the array */ for (i = 0; array[i] != NULL; ++i); } /* realloc, adding a slot for the new pointer */ newarray = (void **)realloc(array, (i + 2) * sizeof (*array)); if (newarray != NULL) { /* Append pointer and terminal NULL */ newarray[i] = pointer; newarray[i+1] = NULL; } return (newarray); }