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