xref: /illumos-gate/usr/src/lib/libnvpair/libnvpair.c (revision 825ba0f2)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <unistd.h>
29 #include <strings.h>
30 #include <sys/types.h>
31 #include <sys/inttypes.h>
32 #include "libnvpair.h"
33 
34 /*
35  * libnvpair - A tools library for manipulating <name, value> pairs.
36  *
37  *	This library provides routines packing an unpacking nv pairs
38  *	for transporting data across process boundaries, transporting
39  *	between kernel and userland, and possibly saving onto disk files.
40  */
41 
42 static void
43 indent(FILE *fp, int depth)
44 {
45 	while (depth-- > 0)
46 		(void) fprintf(fp, "\t");
47 }
48 
49 /*
50  * nvlist_print - Prints elements in an event buffer
51  */
52 static
53 void
54 nvlist_print_with_indent(FILE *fp, nvlist_t *nvl, int depth)
55 {
56 	int i;
57 	char *name;
58 	uint_t nelem;
59 	nvpair_t *nvp;
60 
61 	if (nvl == NULL)
62 		return;
63 
64 	indent(fp, depth);
65 	(void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl));
66 
67 	nvp = nvlist_next_nvpair(nvl, NULL);
68 
69 	while (nvp) {
70 		data_type_t type = nvpair_type(nvp);
71 
72 		indent(fp, depth);
73 		name = nvpair_name(nvp);
74 		(void) fprintf(fp, "\t%s =", name);
75 		nelem = 0;
76 		switch (type) {
77 		case DATA_TYPE_BOOLEAN: {
78 			(void) fprintf(fp, " 1");
79 			break;
80 		}
81 		case DATA_TYPE_BOOLEAN_VALUE: {
82 			boolean_t val;
83 			(void) nvpair_value_boolean_value(nvp, &val);
84 			(void) fprintf(fp, " %d", val);
85 			break;
86 		}
87 		case DATA_TYPE_BYTE: {
88 			uchar_t val;
89 			(void) nvpair_value_byte(nvp, &val);
90 			(void) fprintf(fp, " 0x%2.2x", val);
91 			break;
92 		}
93 		case DATA_TYPE_INT8: {
94 			int8_t val;
95 			(void) nvpair_value_int8(nvp, &val);
96 			(void) fprintf(fp, " %d", val);
97 			break;
98 		}
99 		case DATA_TYPE_UINT8: {
100 			uint8_t val;
101 			(void) nvpair_value_uint8(nvp, &val);
102 			(void) fprintf(fp, " 0x%x", val);
103 			break;
104 		}
105 		case DATA_TYPE_INT16: {
106 			int16_t val;
107 			(void) nvpair_value_int16(nvp, &val);
108 			(void) fprintf(fp, " %d", val);
109 			break;
110 		}
111 		case DATA_TYPE_UINT16: {
112 			uint16_t val;
113 			(void) nvpair_value_uint16(nvp, &val);
114 			(void) fprintf(fp, " 0x%x", val);
115 			break;
116 		}
117 		case DATA_TYPE_INT32: {
118 			int32_t val;
119 			(void) nvpair_value_int32(nvp, &val);
120 			(void) fprintf(fp, " %d", val);
121 			break;
122 		}
123 		case DATA_TYPE_UINT32: {
124 			uint32_t val;
125 			(void) nvpair_value_uint32(nvp, &val);
126 			(void) fprintf(fp, " 0x%x", val);
127 			break;
128 		}
129 		case DATA_TYPE_INT64: {
130 			int64_t val;
131 			(void) nvpair_value_int64(nvp, &val);
132 			(void) fprintf(fp, " %lld", (longlong_t)val);
133 			break;
134 		}
135 		case DATA_TYPE_UINT64: {
136 			uint64_t val;
137 			(void) nvpair_value_uint64(nvp, &val);
138 			(void) fprintf(fp, " 0x%llx", (u_longlong_t)val);
139 			break;
140 		}
141 		case DATA_TYPE_DOUBLE: {
142 			double val;
143 			(void) nvpair_value_double(nvp, &val);
144 			(void) fprintf(fp, " 0x%llf", val);
145 			break;
146 		}
147 		case DATA_TYPE_STRING: {
148 			char *val;
149 			(void) nvpair_value_string(nvp, &val);
150 			(void) fprintf(fp, " %s", val);
151 			break;
152 		}
153 		case DATA_TYPE_BOOLEAN_ARRAY: {
154 			boolean_t *val;
155 			(void) nvpair_value_boolean_array(nvp, &val, &nelem);
156 			for (i = 0; i < nelem; i++)
157 				(void) fprintf(fp, " %d", val[i]);
158 			break;
159 		}
160 		case DATA_TYPE_BYTE_ARRAY: {
161 			uchar_t *val;
162 			(void) nvpair_value_byte_array(nvp, &val, &nelem);
163 			for (i = 0; i < nelem; i++)
164 				(void) fprintf(fp, " 0x%2.2x", val[i]);
165 			break;
166 		}
167 		case DATA_TYPE_INT8_ARRAY: {
168 			int8_t *val;
169 			(void) nvpair_value_int8_array(nvp, &val, &nelem);
170 			for (i = 0; i < nelem; i++)
171 				(void) fprintf(fp, " %d", val[i]);
172 			break;
173 		}
174 		case DATA_TYPE_UINT8_ARRAY: {
175 			uint8_t *val;
176 			(void) nvpair_value_uint8_array(nvp, &val, &nelem);
177 			for (i = 0; i < nelem; i++)
178 				(void) fprintf(fp, " 0x%x", val[i]);
179 			break;
180 		}
181 		case DATA_TYPE_INT16_ARRAY: {
182 			int16_t *val;
183 			(void) nvpair_value_int16_array(nvp, &val, &nelem);
184 			for (i = 0; i < nelem; i++)
185 				(void) fprintf(fp, " %d", val[i]);
186 			break;
187 		}
188 		case DATA_TYPE_UINT16_ARRAY: {
189 			uint16_t *val;
190 			(void) nvpair_value_uint16_array(nvp, &val, &nelem);
191 			for (i = 0; i < nelem; i++)
192 				(void) fprintf(fp, " 0x%x", val[i]);
193 			break;
194 		}
195 		case DATA_TYPE_INT32_ARRAY: {
196 			int32_t *val;
197 			(void) nvpair_value_int32_array(nvp, &val, &nelem);
198 			for (i = 0; i < nelem; i++)
199 				(void) fprintf(fp, " %d", val[i]);
200 			break;
201 		}
202 		case DATA_TYPE_UINT32_ARRAY: {
203 			uint32_t *val;
204 			(void) nvpair_value_uint32_array(nvp, &val, &nelem);
205 			for (i = 0; i < nelem; i++)
206 				(void) fprintf(fp, " 0x%x", val[i]);
207 			break;
208 		}
209 		case DATA_TYPE_INT64_ARRAY: {
210 			int64_t *val;
211 			(void) nvpair_value_int64_array(nvp, &val, &nelem);
212 			for (i = 0; i < nelem; i++)
213 				(void) fprintf(fp, " %lld", (longlong_t)val[i]);
214 			break;
215 		}
216 		case DATA_TYPE_UINT64_ARRAY: {
217 			uint64_t *val;
218 			(void) nvpair_value_uint64_array(nvp, &val, &nelem);
219 			for (i = 0; i < nelem; i++)
220 				(void) fprintf(fp, " 0x%llx",
221 				    (u_longlong_t)val[i]);
222 			break;
223 		}
224 		case DATA_TYPE_STRING_ARRAY: {
225 			char **val;
226 			(void) nvpair_value_string_array(nvp, &val, &nelem);
227 			for (i = 0; i < nelem; i++)
228 				(void) fprintf(fp, " %s", val[i]);
229 			break;
230 		}
231 		case DATA_TYPE_HRTIME: {
232 			hrtime_t val;
233 			(void) nvpair_value_hrtime(nvp, &val);
234 			(void) fprintf(fp, " 0x%llx", val);
235 			break;
236 		}
237 		case DATA_TYPE_NVLIST: {
238 			nvlist_t *val;
239 			(void) nvpair_value_nvlist(nvp, &val);
240 			(void) fprintf(fp, " (embedded nvlist)\n");
241 			nvlist_print_with_indent(fp, val, depth + 1);
242 			indent(fp, depth + 1);
243 			(void) fprintf(fp, "(end %s)\n", name);
244 			break;
245 		}
246 		case DATA_TYPE_NVLIST_ARRAY: {
247 			nvlist_t **val;
248 			(void) nvpair_value_nvlist_array(nvp, &val, &nelem);
249 			(void) fprintf(fp, " (array of embedded nvlists)\n");
250 			for (i = 0; i < nelem; i++) {
251 				indent(fp, depth + 1);
252 				(void) fprintf(fp,
253 				    "(start %s[%d])\n", name, i);
254 				nvlist_print_with_indent(fp, val[i], depth + 1);
255 				indent(fp, depth + 1);
256 				(void) fprintf(fp, "(end %s[%d])\n", name, i);
257 			}
258 			break;
259 		}
260 		default:
261 			(void) fprintf(fp, " unknown data type (%d)", type);
262 			break;
263 		}
264 		(void) fprintf(fp, "\n");
265 		nvp = nvlist_next_nvpair(nvl, nvp);
266 	}
267 }
268 
269 void
270 nvlist_print(FILE *fp, nvlist_t *nvl)
271 {
272 	nvlist_print_with_indent(fp, nvl, 0);
273 }
274 
275 /*
276  * Determine if string 'value' matches 'nvp' value.  The 'value' string is
277  * converted, depending on the type of 'nvp', prior to match.  For numeric
278  * types, a radix independent sscanf conversion of 'value' is used. If 'nvp'
279  * is an array type, 'ai' is the index into the array against which we are
280  * checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass
281  * in a regex_t compilation of value in 'value_regex' to trigger regular
282  * expression string match instead of simple strcmp().
283  *
284  * Return 1 on match, 0 on no-match, and -1 on error.  If the error is
285  * related to value syntax error and 'ep' is non-NULL, *ep will point into
286  * the 'value' string at the location where the error exists.
287  *
288  * NOTE: It may be possible to move the non-regex_t version of this into
289  * common code used by library/kernel/boot.
290  */
291 int
292 nvpair_value_match_regex(nvpair_t *nvp, int ai,
293     char *value, regex_t *value_regex, char **ep)
294 {
295 	char	*evalue;
296 	uint_t	a_len;
297 	int	sr;
298 
299 	if (ep)
300 		*ep = NULL;
301 
302 	if ((nvp == NULL) || (value == NULL))
303 		return (-1);		/* error fail match - invalid args */
304 
305 	/* make sure array and index combination make sense */
306 	if ((nvpair_type_is_array(nvp) && (ai < 0)) ||
307 	    (!nvpair_type_is_array(nvp) && (ai >= 0)))
308 		return (-1);		/* error fail match - bad index */
309 
310 	/* non-string values should be single 'chunk' */
311 	if ((nvpair_type(nvp) != DATA_TYPE_STRING) &&
312 	    (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) {
313 		value += strspn(value, " \t");
314 		evalue = value + strcspn(value, " \t");
315 		if (*evalue) {
316 			if (ep)
317 				*ep = evalue;
318 			return (-1);	/* error fail match - syntax */
319 		}
320 	}
321 
322 	sr = EOF;
323 	switch (nvpair_type(nvp)) {
324 	case DATA_TYPE_STRING: {
325 		char	*val;
326 
327 		/* check string value for match */
328 		if (nvpair_value_string(nvp, &val) == 0) {
329 			if (value_regex) {
330 				if (regexec(value_regex, val,
331 				    (size_t)0, NULL, 0) == 0)
332 					return (1);	/* match */
333 			} else {
334 				if (strcmp(value, val) == 0)
335 					return (1);	/* match */
336 			}
337 		}
338 		break;
339 	}
340 	case DATA_TYPE_STRING_ARRAY: {
341 		char **val_array;
342 
343 		/* check indexed string value of array for match */
344 		if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) &&
345 		    (ai < a_len)) {
346 			if (value_regex) {
347 				if (regexec(value_regex, val_array[ai],
348 				    (size_t)0, NULL, 0) == 0)
349 					return (1);
350 			} else {
351 				if (strcmp(value, val_array[ai]) == 0)
352 					return (1);
353 			}
354 		}
355 		break;
356 	}
357 	case DATA_TYPE_BYTE: {
358 		uchar_t val, val_arg;
359 
360 		/* scanf uchar_t from value and check for match */
361 		sr = sscanf(value, "%c", &val_arg);
362 		if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) &&
363 		    (val == val_arg))
364 			return (1);
365 		break;
366 	}
367 	case DATA_TYPE_BYTE_ARRAY: {
368 		uchar_t *val_array, val_arg;
369 
370 
371 		/* check indexed value of array for match */
372 		sr = sscanf(value, "%c", &val_arg);
373 		if ((sr == 1) &&
374 		    (nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) &&
375 		    (ai < a_len) &&
376 		    (val_array[ai] == val_arg))
377 			return (1);
378 		break;
379 	}
380 	case DATA_TYPE_INT8: {
381 		int8_t val, val_arg;
382 
383 		/* scanf int8_t from value and check for match */
384 		sr = sscanf(value, "%"SCNi8, &val_arg);
385 		if ((sr == 1) &&
386 		    (nvpair_value_int8(nvp, &val) == 0) &&
387 		    (val == val_arg))
388 			return (1);
389 		break;
390 	}
391 	case DATA_TYPE_INT8_ARRAY: {
392 		int8_t *val_array, val_arg;
393 
394 		/* check indexed value of array for match */
395 		sr = sscanf(value, "%"SCNi8, &val_arg);
396 		if ((sr == 1) &&
397 		    (nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) &&
398 		    (ai < a_len) &&
399 		    (val_array[ai] == val_arg))
400 			return (1);
401 		break;
402 	}
403 	case DATA_TYPE_UINT8: {
404 		uint8_t val, val_arg;
405 
406 		/* scanf uint8_t from value and check for match */
407 		sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
408 		if ((sr == 1) &&
409 		    (nvpair_value_uint8(nvp, &val) == 0) &&
410 		    (val == val_arg))
411 			return (1);
412 		break;
413 	}
414 	case DATA_TYPE_UINT8_ARRAY: {
415 		uint8_t *val_array, val_arg;
416 
417 		/* check indexed value of array for match */
418 		sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
419 		if ((sr == 1) &&
420 		    (nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) &&
421 		    (ai < a_len) &&
422 		    (val_array[ai] == val_arg))
423 			return (1);
424 		break;
425 	}
426 	case DATA_TYPE_INT16: {
427 		int16_t val, val_arg;
428 
429 		/* scanf int16_t from value and check for match */
430 		sr = sscanf(value, "%"SCNi16, &val_arg);
431 		if ((sr == 1) &&
432 		    (nvpair_value_int16(nvp, &val) == 0) &&
433 		    (val == val_arg))
434 			return (1);
435 		break;
436 	}
437 	case DATA_TYPE_INT16_ARRAY: {
438 		int16_t *val_array, val_arg;
439 
440 		/* check indexed value of array for match */
441 		sr = sscanf(value, "%"SCNi16, &val_arg);
442 		if ((sr == 1) &&
443 		    (nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) &&
444 		    (ai < a_len) &&
445 		    (val_array[ai] == val_arg))
446 			return (1);
447 		break;
448 	}
449 	case DATA_TYPE_UINT16: {
450 		uint16_t val, val_arg;
451 
452 		/* scanf uint16_t from value and check for match */
453 		sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
454 		if ((sr == 1) &&
455 		    (nvpair_value_uint16(nvp, &val) == 0) &&
456 		    (val == val_arg))
457 			return (1);
458 		break;
459 	}
460 	case DATA_TYPE_UINT16_ARRAY: {
461 		uint16_t *val_array, val_arg;
462 
463 		/* check indexed value of array for match */
464 		sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
465 		if ((sr == 1) &&
466 		    (nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) &&
467 		    (ai < a_len) &&
468 		    (val_array[ai] == val_arg))
469 			return (1);
470 		break;
471 	}
472 	case DATA_TYPE_INT32: {
473 		int32_t val, val_arg;
474 
475 		/* scanf int32_t from value and check for match */
476 		sr = sscanf(value, "%"SCNi32, &val_arg);
477 		if ((sr == 1) &&
478 		    (nvpair_value_int32(nvp, &val) == 0) &&
479 		    (val == val_arg))
480 			return (1);
481 		break;
482 	}
483 	case DATA_TYPE_INT32_ARRAY: {
484 		int32_t *val_array, val_arg;
485 
486 		/* check indexed value of array for match */
487 		sr = sscanf(value, "%"SCNi32, &val_arg);
488 		if ((sr == 1) &&
489 		    (nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) &&
490 		    (ai < a_len) &&
491 		    (val_array[ai] == val_arg))
492 			return (1);
493 		break;
494 	}
495 	case DATA_TYPE_UINT32: {
496 		uint32_t val, val_arg;
497 
498 		/* scanf uint32_t from value and check for match */
499 		sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
500 		if ((sr == 1) &&
501 		    (nvpair_value_uint32(nvp, &val) == 0) &&
502 		    (val == val_arg))
503 			return (1);
504 		break;
505 	}
506 	case DATA_TYPE_UINT32_ARRAY: {
507 		uint32_t *val_array, val_arg;
508 
509 		/* check indexed value of array for match */
510 		sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
511 		if ((sr == 1) &&
512 		    (nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) &&
513 		    (ai < a_len) &&
514 		    (val_array[ai] == val_arg))
515 			return (1);
516 		break;
517 	}
518 	case DATA_TYPE_INT64: {
519 		int64_t val, val_arg;
520 
521 		/* scanf int64_t from value and check for match */
522 		sr = sscanf(value, "%"SCNi64, &val_arg);
523 		if ((sr == 1) &&
524 		    (nvpair_value_int64(nvp, &val) == 0) &&
525 		    (val == val_arg))
526 			return (1);
527 		break;
528 	}
529 	case DATA_TYPE_INT64_ARRAY: {
530 		int64_t *val_array, val_arg;
531 
532 		/* check indexed value of array for match */
533 		sr = sscanf(value, "%"SCNi64, &val_arg);
534 		if ((sr == 1) &&
535 		    (nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) &&
536 		    (ai < a_len) &&
537 		    (val_array[ai] == val_arg))
538 				return (1);
539 		break;
540 	}
541 	case DATA_TYPE_UINT64: {
542 		uint64_t val_arg, val;
543 
544 		/* scanf uint64_t from value and check for match */
545 		sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
546 		if ((sr == 1) &&
547 		    (nvpair_value_uint64(nvp, &val) == 0) &&
548 		    (val == val_arg))
549 			return (1);
550 		break;
551 	}
552 	case DATA_TYPE_UINT64_ARRAY: {
553 		uint64_t *val_array, val_arg;
554 
555 		/* check indexed value of array for match */
556 		sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
557 		if ((sr == 1) &&
558 		    (nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) &&
559 		    (ai < a_len) &&
560 		    (val_array[ai] == val_arg))
561 			return (1);
562 		break;
563 	}
564 	case DATA_TYPE_BOOLEAN_VALUE: {
565 		boolean_t val, val_arg;
566 
567 		/* scanf boolean_t from value and check for match */
568 		sr = sscanf(value, "%"SCNi32, &val_arg);
569 		if ((sr == 1) &&
570 		    (nvpair_value_boolean_value(nvp, &val) == 0) &&
571 		    (val == val_arg))
572 			return (1);
573 		break;
574 	}
575 	case DATA_TYPE_BOOLEAN_ARRAY: {
576 		boolean_t *val_array, val_arg;
577 
578 		/* check indexed value of array for match */
579 		sr = sscanf(value, "%"SCNi32, &val_arg);
580 		if ((sr == 1) &&
581 		    (nvpair_value_boolean_array(nvp,
582 		    &val_array, &a_len) == 0) &&
583 		    (ai < a_len) &&
584 		    (val_array[ai] == val_arg))
585 			return (1);
586 		break;
587 	}
588 	case DATA_TYPE_HRTIME:
589 	case DATA_TYPE_NVLIST:
590 	case DATA_TYPE_NVLIST_ARRAY:
591 	case DATA_TYPE_BOOLEAN:
592 	case DATA_TYPE_DOUBLE:
593 	case DATA_TYPE_UNKNOWN:
594 	default:
595 		/*
596 		 * unknown/unsupported data type
597 		 */
598 		return (-1);		/* error fail match */
599 	}
600 
601 	/*
602 	 * check to see if sscanf failed conversion, return approximate
603 	 * pointer to problem
604 	 */
605 	if (sr != 1) {
606 		if (ep)
607 			*ep = value;
608 		return (-1);		/* error fail match  - syntax */
609 	}
610 
611 	return (0);			/* fail match */
612 }
613 
614 int
615 nvpair_value_match(nvpair_t *nvp, int ai, char *value, char **ep)
616 {
617 	return (nvpair_value_match_regex(nvp, ai, value, NULL, ep));
618 }
619