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