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