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