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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <strings.h> 31 #include <pool.h> 32 #include "pool_internal.h" 33 34 /* 35 * libpool Value Manipulation Routines 36 * 37 * pool_value.c implements the value (pool_value_t) functionality for 38 * libpool. The datatypes supported are: uint64_t, int64_t, double, 39 * uchar_t (boolean), const char * (string). Values are used to 40 * represent data stored to and retrieved from the datastore in a 41 * simple discriminated union. 42 * 43 * Values are dynamically allocated using pool_value_alloc() and 44 * destroyed using pool_value_free(). 45 * 46 * Values may be allocated statically for internal use in 47 * libpool. Statically allocated pool_value_t variables must be 48 * initialised with the POOL_VALUE_INITIALIZER macro, otherwise the 49 * results are unpredictable. 50 * 51 * A pool_value_t variable can be used to store values in any of the 52 * supported datatypes. 53 * 54 * A pool_value_t's name and string value are limited in size to 55 * PV_NAME_MAX_LEN and PV_VALUE_MAX_LEN respectively. Attempting to 56 * store values which are greater than this in length will fail with a 57 * POE_BADPARAM error. 58 */ 59 60 /* 61 * Get the uint64_t data held by the value. If the data type isn't 62 * uint64_t return PO_FAIL and set pool_error to be POE_BAD_PROP_TYPE. 63 */ 64 int 65 pool_value_get_uint64(const pool_value_t *pv, uint64_t *result) 66 { 67 if (pv->pv_class != POC_UINT) { 68 pool_seterror(POE_BAD_PROP_TYPE); 69 return (PO_FAIL); 70 } 71 *result = pv->pv_u.u; 72 return (PO_SUCCESS); 73 } 74 75 /* 76 * Get the int64_t data held by the value. If the data type isn't 77 * int64_t return PO_FAIL and set pool_error to be POE_BAD_PROP_TYPE. 78 */ 79 int 80 pool_value_get_int64(const pool_value_t *pv, int64_t *result) 81 { 82 if (pv->pv_class != POC_INT) { 83 pool_seterror(POE_BAD_PROP_TYPE); 84 return (PO_FAIL); 85 } 86 *result = pv->pv_u.i; 87 return (PO_SUCCESS); 88 } 89 90 /* 91 * Get the double data held by the value. If the data type isn't 92 * double return PO_FAIL and set pool_error to be POE_BAD_PROP_TYPE. 93 */ 94 95 int 96 pool_value_get_double(const pool_value_t *pv, double *result) 97 { 98 if (pv->pv_class != POC_DOUBLE) { 99 pool_seterror(POE_BAD_PROP_TYPE); 100 return (PO_FAIL); 101 } 102 *result = pv->pv_u.d; 103 return (PO_SUCCESS); 104 } 105 106 /* 107 * Get the boolean data held by the value. If the data type isn't 108 * boolean return PO_FAIL and set pool_error to be POE_BAD_PROP_TYPE. 109 */ 110 int 111 pool_value_get_bool(const pool_value_t *pv, uchar_t *result) 112 { 113 if (pv->pv_class != POC_BOOL) { 114 pool_seterror(POE_BAD_PROP_TYPE); 115 return (PO_FAIL); 116 } 117 *result = pv->pv_u.b; 118 return (PO_SUCCESS); 119 } 120 121 /* 122 * Get the string data held by the value. If the data type isn't 123 * string return PO_FAIL and set pool_error to be POE_BAD_PROP_TYPE. 124 */ 125 int 126 pool_value_get_string(const pool_value_t *pv, const char **result) 127 { 128 if (pv->pv_class != POC_STRING) { 129 pool_seterror(POE_BAD_PROP_TYPE); 130 return (PO_FAIL); 131 } 132 *result = pv->pv_u.s; 133 return (PO_SUCCESS); 134 } 135 136 /* 137 * Get the type of the data held by the value. If the value has never 138 * been used to store data, then the type is POC_INVAL. 139 */ 140 pool_value_class_t 141 pool_value_get_type(const pool_value_t *pv) 142 { 143 return (pv->pv_class); 144 } 145 146 /* 147 * Set the value's data to the supplied uint64_t data. Update the type 148 * of the value data to POC_UINT. 149 */ 150 void 151 pool_value_set_uint64(pool_value_t *pv, uint64_t val) 152 { 153 if (pv->pv_class == POC_STRING) 154 atom_free(pv->pv_u.s); 155 pv->pv_class = POC_UINT; 156 pv->pv_u.u = val; 157 } 158 159 /* 160 * Set the value's data to the supplied int64_t data. Update the type 161 * of the value data to POC_INT. 162 */ 163 void 164 pool_value_set_int64(pool_value_t *pv, int64_t val) 165 { 166 if (pv->pv_class == POC_STRING) 167 atom_free(pv->pv_u.s); 168 pv->pv_class = POC_INT; 169 pv->pv_u.i = val; 170 } 171 172 /* 173 * Set the value's data to the supplied double data. Update the type 174 * of the value data to POC_DOUBLE. 175 */ 176 177 void 178 pool_value_set_double(pool_value_t *pv, double val) 179 { 180 if (pv->pv_class == POC_STRING) 181 atom_free(pv->pv_u.s); 182 pv->pv_class = POC_DOUBLE; 183 pv->pv_u.d = val; 184 } 185 186 /* 187 * Set the value's data to the supplied uchar_t data. Update the type 188 * of the value data to POC_BOOL. 189 */ 190 void 191 pool_value_set_bool(pool_value_t *pv, uchar_t val) 192 { 193 if (pv->pv_class == POC_STRING) 194 atom_free(pv->pv_u.s); 195 pv->pv_class = POC_BOOL; 196 pv->pv_u.b = !!val; /* Lock value at 0 or 1 */ 197 } 198 199 /* 200 * Try to make an internal copy of the val, returning PO_SUCCESS or 201 * PO_FAIL if the copy works or fails. 202 */ 203 int 204 pool_value_set_string(pool_value_t *pv, const char *val) 205 { 206 if (pv->pv_class == POC_STRING) 207 atom_free(pv->pv_u.s); 208 pv->pv_class = POC_STRING; 209 if (val == NULL || strlen(val) >= PV_VALUE_MAX_LEN) { 210 pool_seterror(POE_BADPARAM); 211 return (PO_FAIL); 212 } else { 213 if ((pv->pv_u.s = atom_string(val)) == NULL) 214 return (PO_FAIL); 215 } 216 return (PO_SUCCESS); 217 } 218 219 /* 220 * Allocate a pool_value_t structure and initialise it to 0. Set the 221 * type to POC_INVAL and return a pointer to the new pool_value_t. If 222 * memory allocation fails, set POE_SYSTEM and return NULL. 223 */ 224 pool_value_t * 225 pool_value_alloc(void) 226 { 227 pool_value_t *val; 228 229 if ((val = malloc(sizeof (pool_value_t))) == NULL) { 230 pool_seterror(POE_SYSTEM); 231 return (NULL); 232 } 233 (void) memset(val, 0, sizeof (pool_value_t)); 234 val->pv_class = POC_INVAL; 235 return (val); 236 } 237 238 /* 239 * Free any atoms associated with the value and then free the value 240 * itself. 241 */ 242 void 243 pool_value_free(pool_value_t *pv) 244 { 245 if (pv->pv_name) 246 atom_free(pv->pv_name); 247 if (pv->pv_class == POC_STRING) 248 atom_free(pv->pv_u.s); 249 free(pv); 250 } 251 252 /* 253 * Return a pointer to the name of the value. This may be NULL if the 254 * name has never been set. 255 */ 256 const char * 257 pool_value_get_name(const pool_value_t *pv) 258 { 259 return (pv->pv_name); 260 } 261 262 /* 263 * Set the name of the value to the supplied name. 264 */ 265 int 266 pool_value_set_name(pool_value_t *pv, const char *name) 267 { 268 if (name == NULL || strlen(name) >= PV_NAME_MAX_LEN) { 269 pool_seterror(POE_BADPARAM); 270 return (PO_FAIL); 271 } else { 272 if (pv->pv_name) 273 atom_free(pv->pv_name); 274 if ((pv->pv_name = atom_string(name)) == NULL) 275 return (PO_FAIL); 276 } 277 return (PO_SUCCESS); 278 } 279 280 /* 281 * Use the supplied nvpair_t to set the name, type and value of the 282 * supplied pool_value_t. 283 * 284 * Return: PO_SUCCESS/PO_FAIL 285 */ 286 int 287 pool_value_from_nvpair(pool_value_t *pv, nvpair_t *pn) 288 { 289 uchar_t bval; 290 uint64_t uval; 291 int64_t ival; 292 double dval; 293 uint_t nelem; 294 uchar_t *dval_b; 295 char *sval; 296 297 if (pool_value_set_name(pv, nvpair_name(pn)) != PO_SUCCESS) 298 return (PO_FAIL); 299 switch (nvpair_type(pn)) { 300 case DATA_TYPE_BYTE: 301 if (nvpair_value_byte(pn, &bval) != 0) { 302 pool_seterror(POE_SYSTEM); 303 return (PO_FAIL); 304 } 305 pool_value_set_bool(pv, bval); 306 break; 307 case DATA_TYPE_BYTE_ARRAY: 308 if (nvpair_value_byte_array(pn, &dval_b, &nelem) != 0) { 309 pool_seterror(POE_SYSTEM); 310 return (PO_FAIL); 311 } 312 (void) memcpy(&dval, dval_b, sizeof (double)); 313 pool_value_set_double(pv, dval); 314 break; 315 case DATA_TYPE_INT64: 316 if (nvpair_value_int64(pn, &ival) != 0) { 317 pool_seterror(POE_SYSTEM); 318 return (PO_FAIL); 319 } 320 pool_value_set_int64(pv, ival); 321 break; 322 case DATA_TYPE_UINT64: 323 if (nvpair_value_uint64(pn, &uval) != 0) { 324 pool_seterror(POE_SYSTEM); 325 return (PO_FAIL); 326 } 327 pool_value_set_uint64(pv, uval); 328 break; 329 case DATA_TYPE_STRING: 330 if (nvpair_value_string(pn, &sval) != 0) { 331 pool_seterror(POE_SYSTEM); 332 return (PO_FAIL); 333 } 334 if (pool_value_set_string(pv, sval) != PO_SUCCESS) 335 return (PO_FAIL); 336 break; 337 default: 338 pool_seterror(POE_SYSTEM); 339 return (PO_FAIL); 340 } 341 return (PO_SUCCESS); 342 } 343 344 /* 345 * Check to see if the values held by two supplied values are 346 * equal. First compare the pointers to see if we are comparing to 347 * ourselves, if we are return PO_TRUE. If not, get the types and 348 * ensure they match, if they don't return PO_FALSE. Then do a type 349 * specific comparison returning PO_TRUE or PO_FALSE accordingly. 350 */ 351 int 352 pool_value_equal(pool_value_t *pv1, pool_value_t *pv2) 353 { 354 uint64_t uval1, uval2; 355 int64_t ival1, ival2; 356 double dval1, dval2; 357 uchar_t bval1, bval2; 358 const char *sval1, *sval2; 359 pool_value_class_t type; 360 361 if (pv1 == pv2) /* optimisation */ 362 return (PO_TRUE); 363 364 type = pool_value_get_type(pv1); 365 if (type != pool_value_get_type(pv2)) 366 return (PO_FALSE); 367 368 switch (type) { 369 case POC_UINT: 370 (void) pool_value_get_uint64(pv1, &uval1); 371 (void) pool_value_get_uint64(pv2, &uval2); 372 if (uval1 == uval2) 373 return (PO_TRUE); 374 break; 375 case POC_INT: 376 (void) pool_value_get_int64(pv1, &ival1); 377 (void) pool_value_get_int64(pv2, &ival2); 378 if (ival1 == ival2) 379 return (PO_TRUE); 380 break; 381 case POC_DOUBLE: 382 (void) pool_value_get_double(pv1, &dval1); 383 (void) pool_value_get_double(pv2, &dval2); 384 if (dval1 == dval2) 385 return (PO_TRUE); 386 break; 387 case POC_BOOL: 388 (void) pool_value_get_bool(pv1, &bval1); 389 (void) pool_value_get_bool(pv2, &bval2); 390 if (bval1 == bval2) 391 return (PO_TRUE); 392 break; 393 case POC_STRING: 394 (void) pool_value_get_string(pv1, &sval1); 395 (void) pool_value_get_string(pv2, &sval2); 396 if (strcmp(sval1, sval2) == 0) 397 return (PO_TRUE); 398 break; 399 } 400 return (PO_FALSE); 401 } 402 403 #ifdef DEBUG 404 /* 405 * Trace pool_value_t details using dprintf 406 */ 407 void 408 pool_value_dprintf(const pool_value_t *pv) 409 { 410 const char *class_name[] = { 411 "POC_UINT", 412 "POC_INT", 413 "POC_DOUBLE", 414 "POC_BOOL", 415 "POC_STRING" 416 }; 417 418 dprintf("name: %s\n", pv->pv_name ? pv->pv_name : "NULL"); 419 if (pv->pv_class >= POC_UINT && pv->pv_class <= POC_STRING) 420 dprintf("type: %s\n", class_name[pv->pv_class]); 421 else 422 dprintf("type: POC_INVAL\n"); 423 switch (pv->pv_class) { 424 case POC_UINT: 425 dprintf("value: %llu\n", pv->pv_u.u); 426 break; 427 case POC_INT: 428 dprintf("value: %lld\n", pv->pv_u.i); 429 break; 430 case POC_DOUBLE: 431 dprintf("value: %f\n", pv->pv_u.d); 432 break; 433 case POC_BOOL: 434 dprintf("value: %s\n", pv->pv_u.b ? "true" : "false"); 435 break; 436 case POC_STRING: 437 dprintf("value: %s\n", pv->pv_u.s); 438 break; 439 default: 440 dprintf("value: invalid\n"); 441 break; 442 } 443 } 444 #endif /* DEBUG */ 445