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
pool_value_get_uint64(const pool_value_t * pv,uint64_t * result)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
pool_value_get_int64(const pool_value_t * pv,int64_t * result)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
pool_value_get_double(const pool_value_t * pv,double * result)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
pool_value_get_bool(const pool_value_t * pv,uchar_t * result)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
pool_value_get_string(const pool_value_t * pv,const char ** result)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
pool_value_get_type(const pool_value_t * pv)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
pool_value_set_uint64(pool_value_t * pv,uint64_t val)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
pool_value_set_int64(pool_value_t * pv,int64_t val)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
pool_value_set_double(pool_value_t * pv,double val)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
pool_value_set_bool(pool_value_t * pv,uchar_t val)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
pool_value_set_string(pool_value_t * pv,const char * val)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 *
pool_value_alloc(void)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
pool_value_free(pool_value_t * pv)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 *
pool_value_get_name(const pool_value_t * pv)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
pool_value_set_name(pool_value_t * pv,const char * name)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
pool_value_from_nvpair(pool_value_t * pv,nvpair_t * pn)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
pool_value_equal(pool_value_t * pv1,pool_value_t * pv2)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
pool_value_dprintf(const pool_value_t * pv)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