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_STRING: { 142 char *val; 143 (void) nvpair_value_string(nvp, &val); 144 (void) fprintf(fp, " %s", val); 145 break; 146 } 147 case DATA_TYPE_BOOLEAN_ARRAY: { 148 boolean_t *val; 149 (void) nvpair_value_boolean_array(nvp, &val, &nelem); 150 for (i = 0; i < nelem; i++) 151 (void) fprintf(fp, " %d", val[i]); 152 break; 153 } 154 case DATA_TYPE_BYTE_ARRAY: { 155 uchar_t *val; 156 (void) nvpair_value_byte_array(nvp, &val, &nelem); 157 for (i = 0; i < nelem; i++) 158 (void) fprintf(fp, " 0x%2.2x", val[i]); 159 break; 160 } 161 case DATA_TYPE_INT8_ARRAY: { 162 int8_t *val; 163 (void) nvpair_value_int8_array(nvp, &val, &nelem); 164 for (i = 0; i < nelem; i++) 165 (void) fprintf(fp, " %d", val[i]); 166 break; 167 } 168 case DATA_TYPE_UINT8_ARRAY: { 169 uint8_t *val; 170 (void) nvpair_value_uint8_array(nvp, &val, &nelem); 171 for (i = 0; i < nelem; i++) 172 (void) fprintf(fp, " 0x%x", val[i]); 173 break; 174 } 175 case DATA_TYPE_INT16_ARRAY: { 176 int16_t *val; 177 (void) nvpair_value_int16_array(nvp, &val, &nelem); 178 for (i = 0; i < nelem; i++) 179 (void) fprintf(fp, " %d", val[i]); 180 break; 181 } 182 case DATA_TYPE_UINT16_ARRAY: { 183 uint16_t *val; 184 (void) nvpair_value_uint16_array(nvp, &val, &nelem); 185 for (i = 0; i < nelem; i++) 186 (void) fprintf(fp, " 0x%x", val[i]); 187 break; 188 } 189 case DATA_TYPE_INT32_ARRAY: { 190 int32_t *val; 191 (void) nvpair_value_int32_array(nvp, &val, &nelem); 192 for (i = 0; i < nelem; i++) 193 (void) fprintf(fp, " %d", val[i]); 194 break; 195 } 196 case DATA_TYPE_UINT32_ARRAY: { 197 uint32_t *val; 198 (void) nvpair_value_uint32_array(nvp, &val, &nelem); 199 for (i = 0; i < nelem; i++) 200 (void) fprintf(fp, " 0x%x", val[i]); 201 break; 202 } 203 case DATA_TYPE_INT64_ARRAY: { 204 int64_t *val; 205 (void) nvpair_value_int64_array(nvp, &val, &nelem); 206 for (i = 0; i < nelem; i++) 207 (void) fprintf(fp, " %lld", (longlong_t)val[i]); 208 break; 209 } 210 case DATA_TYPE_UINT64_ARRAY: { 211 uint64_t *val; 212 (void) nvpair_value_uint64_array(nvp, &val, &nelem); 213 for (i = 0; i < nelem; i++) 214 (void) fprintf(fp, " 0x%llx", 215 (u_longlong_t)val[i]); 216 break; 217 } 218 case DATA_TYPE_STRING_ARRAY: { 219 char **val; 220 (void) nvpair_value_string_array(nvp, &val, &nelem); 221 for (i = 0; i < nelem; i++) 222 (void) fprintf(fp, " %s", val[i]); 223 break; 224 } 225 case DATA_TYPE_HRTIME: { 226 hrtime_t val; 227 (void) nvpair_value_hrtime(nvp, &val); 228 (void) fprintf(fp, " 0x%llx", val); 229 break; 230 } 231 case DATA_TYPE_NVLIST: { 232 nvlist_t *val; 233 (void) nvpair_value_nvlist(nvp, &val); 234 (void) fprintf(fp, " (embedded nvlist)\n"); 235 nvlist_print_with_indent(fp, val, depth + 1); 236 indent(fp, depth + 1); 237 (void) fprintf(fp, "(end %s)\n", name); 238 break; 239 } 240 case DATA_TYPE_NVLIST_ARRAY: { 241 nvlist_t **val; 242 (void) nvpair_value_nvlist_array(nvp, &val, &nelem); 243 (void) fprintf(fp, " (array of embedded nvlists)\n"); 244 for (i = 0; i < nelem; i++) { 245 indent(fp, depth + 1); 246 (void) fprintf(fp, 247 "(start %s[%d])\n", name, i); 248 nvlist_print_with_indent(fp, val[i], depth + 1); 249 indent(fp, depth + 1); 250 (void) fprintf(fp, "(end %s[%d])\n", name, i); 251 } 252 break; 253 } 254 default: 255 (void) fprintf(fp, " unknown data type (%d)", type); 256 break; 257 } 258 (void) fprintf(fp, "\n"); 259 nvp = nvlist_next_nvpair(nvl, nvp); 260 } 261 } 262 263 void 264 nvlist_print(FILE *fp, nvlist_t *nvl) 265 { 266 nvlist_print_with_indent(fp, nvl, 0); 267 } 268 269 /* 270 * Determine if string 'value' matches 'nvp' value. The 'value' string is 271 * converted, depending on the type of 'nvp', prior to match. For numeric 272 * types, a radix independent sscanf conversion of 'value' is used. If 'nvp' 273 * is an array type, 'ai' is the index into the array against which we are 274 * checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass 275 * in a regex_t compilation of value in 'value_regex' to trigger regular 276 * expression string match instead of simple strcmp(). 277 * 278 * Return 1 on match, 0 on no-match, and -1 on error. If the error is 279 * related to value syntax error and 'ep' is non-NULL, *ep will point into 280 * the 'value' string at the location where the error exists. 281 * 282 * NOTE: It may be possible to move the non-regex_t version of this into 283 * common code used by library/kernel/boot. 284 */ 285 int 286 nvpair_value_match_regex(nvpair_t *nvp, int ai, 287 char *value, regex_t *value_regex, char **ep) 288 { 289 char *evalue; 290 uint_t a_len; 291 int sr; 292 293 if (ep) 294 *ep = NULL; 295 296 if ((nvp == NULL) || (value == NULL)) 297 return (-1); /* error fail match - invalid args */ 298 299 /* make sure array and index combination make sense */ 300 if ((nvpair_type_is_array(nvp) && (ai < 0)) || 301 (!nvpair_type_is_array(nvp) && (ai >= 0))) 302 return (-1); /* error fail match - bad index */ 303 304 /* non-string values should be single 'chunk' */ 305 if ((nvpair_type(nvp) != DATA_TYPE_STRING) && 306 (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) { 307 value += strspn(value, " \t"); 308 evalue = value + strcspn(value, " \t"); 309 if (*evalue) { 310 if (ep) 311 *ep = evalue; 312 return (-1); /* error fail match - syntax */ 313 } 314 } 315 316 sr = EOF; 317 switch (nvpair_type(nvp)) { 318 case DATA_TYPE_STRING: { 319 char *val; 320 321 /* check string value for match */ 322 if (nvpair_value_string(nvp, &val) == 0) { 323 if (value_regex) { 324 if (regexec(value_regex, val, 325 (size_t)0, NULL, 0) == 0) 326 return (1); /* match */ 327 } else { 328 if (strcmp(value, val) == 0) 329 return (1); /* match */ 330 } 331 } 332 break; 333 } 334 case DATA_TYPE_STRING_ARRAY: { 335 char **val_array; 336 337 /* check indexed string value of array for match */ 338 if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) && 339 (ai < a_len)) { 340 if (value_regex) { 341 if (regexec(value_regex, val_array[ai], 342 (size_t)0, NULL, 0) == 0) 343 return (1); 344 } else { 345 if (strcmp(value, val_array[ai]) == 0) 346 return (1); 347 } 348 } 349 break; 350 } 351 case DATA_TYPE_BYTE: { 352 uchar_t val, val_arg; 353 354 /* scanf uchar_t from value and check for match */ 355 sr = sscanf(value, "%c", &val_arg); 356 if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) && 357 (val == val_arg)) 358 return (1); 359 break; 360 } 361 case DATA_TYPE_BYTE_ARRAY: { 362 uchar_t *val_array, val_arg; 363 364 365 /* check indexed value of array for match */ 366 sr = sscanf(value, "%c", &val_arg); 367 if ((sr == 1) && 368 (nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) && 369 (ai < a_len) && 370 (val_array[ai] == val_arg)) 371 return (1); 372 break; 373 } 374 case DATA_TYPE_INT8: { 375 int8_t val, val_arg; 376 377 /* scanf int8_t from value and check for match */ 378 sr = sscanf(value, "%"SCNi8, &val_arg); 379 if ((sr == 1) && 380 (nvpair_value_int8(nvp, &val) == 0) && 381 (val == val_arg)) 382 return (1); 383 break; 384 } 385 case DATA_TYPE_INT8_ARRAY: { 386 int8_t *val_array, val_arg; 387 388 /* check indexed value of array for match */ 389 sr = sscanf(value, "%"SCNi8, &val_arg); 390 if ((sr == 1) && 391 (nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) && 392 (ai < a_len) && 393 (val_array[ai] == val_arg)) 394 return (1); 395 break; 396 } 397 case DATA_TYPE_UINT8: { 398 uint8_t val, val_arg; 399 400 /* scanf uint8_t from value and check for match */ 401 sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg); 402 if ((sr == 1) && 403 (nvpair_value_uint8(nvp, &val) == 0) && 404 (val == val_arg)) 405 return (1); 406 break; 407 } 408 case DATA_TYPE_UINT8_ARRAY: { 409 uint8_t *val_array, val_arg; 410 411 /* check indexed value of array for match */ 412 sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg); 413 if ((sr == 1) && 414 (nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) && 415 (ai < a_len) && 416 (val_array[ai] == val_arg)) 417 return (1); 418 break; 419 } 420 case DATA_TYPE_INT16: { 421 int16_t val, val_arg; 422 423 /* scanf int16_t from value and check for match */ 424 sr = sscanf(value, "%"SCNi16, &val_arg); 425 if ((sr == 1) && 426 (nvpair_value_int16(nvp, &val) == 0) && 427 (val == val_arg)) 428 return (1); 429 break; 430 } 431 case DATA_TYPE_INT16_ARRAY: { 432 int16_t *val_array, val_arg; 433 434 /* check indexed value of array for match */ 435 sr = sscanf(value, "%"SCNi16, &val_arg); 436 if ((sr == 1) && 437 (nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) && 438 (ai < a_len) && 439 (val_array[ai] == val_arg)) 440 return (1); 441 break; 442 } 443 case DATA_TYPE_UINT16: { 444 uint16_t val, val_arg; 445 446 /* scanf uint16_t from value and check for match */ 447 sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg); 448 if ((sr == 1) && 449 (nvpair_value_uint16(nvp, &val) == 0) && 450 (val == val_arg)) 451 return (1); 452 break; 453 } 454 case DATA_TYPE_UINT16_ARRAY: { 455 uint16_t *val_array, val_arg; 456 457 /* check indexed value of array for match */ 458 sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg); 459 if ((sr == 1) && 460 (nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) && 461 (ai < a_len) && 462 (val_array[ai] == val_arg)) 463 return (1); 464 break; 465 } 466 case DATA_TYPE_INT32: { 467 int32_t val, val_arg; 468 469 /* scanf int32_t from value and check for match */ 470 sr = sscanf(value, "%"SCNi32, &val_arg); 471 if ((sr == 1) && 472 (nvpair_value_int32(nvp, &val) == 0) && 473 (val == val_arg)) 474 return (1); 475 break; 476 } 477 case DATA_TYPE_INT32_ARRAY: { 478 int32_t *val_array, val_arg; 479 480 /* check indexed value of array for match */ 481 sr = sscanf(value, "%"SCNi32, &val_arg); 482 if ((sr == 1) && 483 (nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) && 484 (ai < a_len) && 485 (val_array[ai] == val_arg)) 486 return (1); 487 break; 488 } 489 case DATA_TYPE_UINT32: { 490 uint32_t val, val_arg; 491 492 /* scanf uint32_t from value and check for match */ 493 sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg); 494 if ((sr == 1) && 495 (nvpair_value_uint32(nvp, &val) == 0) && 496 (val == val_arg)) 497 return (1); 498 break; 499 } 500 case DATA_TYPE_UINT32_ARRAY: { 501 uint32_t *val_array, val_arg; 502 503 /* check indexed value of array for match */ 504 sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg); 505 if ((sr == 1) && 506 (nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) && 507 (ai < a_len) && 508 (val_array[ai] == val_arg)) 509 return (1); 510 break; 511 } 512 case DATA_TYPE_INT64: { 513 int64_t val, val_arg; 514 515 /* scanf int64_t from value and check for match */ 516 sr = sscanf(value, "%"SCNi64, &val_arg); 517 if ((sr == 1) && 518 (nvpair_value_int64(nvp, &val) == 0) && 519 (val == val_arg)) 520 return (1); 521 break; 522 } 523 case DATA_TYPE_INT64_ARRAY: { 524 int64_t *val_array, val_arg; 525 526 /* check indexed value of array for match */ 527 sr = sscanf(value, "%"SCNi64, &val_arg); 528 if ((sr == 1) && 529 (nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) && 530 (ai < a_len) && 531 (val_array[ai] == val_arg)) 532 return (1); 533 break; 534 } 535 case DATA_TYPE_UINT64: { 536 uint64_t val_arg, val; 537 538 /* scanf uint64_t from value and check for match */ 539 sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg); 540 if ((sr == 1) && 541 (nvpair_value_uint64(nvp, &val) == 0) && 542 (val == val_arg)) 543 return (1); 544 break; 545 } 546 case DATA_TYPE_UINT64_ARRAY: { 547 uint64_t *val_array, val_arg; 548 549 /* check indexed value of array for match */ 550 sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg); 551 if ((sr == 1) && 552 (nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) && 553 (ai < a_len) && 554 (val_array[ai] == val_arg)) 555 return (1); 556 break; 557 } 558 case DATA_TYPE_BOOLEAN_VALUE: { 559 boolean_t val, val_arg; 560 561 /* scanf boolean_t from value and check for match */ 562 sr = sscanf(value, "%"SCNi32, &val_arg); 563 if ((sr == 1) && 564 (nvpair_value_boolean_value(nvp, &val) == 0) && 565 (val == val_arg)) 566 return (1); 567 break; 568 } 569 case DATA_TYPE_BOOLEAN_ARRAY: { 570 boolean_t *val_array, val_arg; 571 572 /* check indexed value of array for match */ 573 sr = sscanf(value, "%"SCNi32, &val_arg); 574 if ((sr == 1) && 575 (nvpair_value_boolean_array(nvp, 576 &val_array, &a_len) == 0) && 577 (ai < a_len) && 578 (val_array[ai] == val_arg)) 579 return (1); 580 break; 581 } 582 case DATA_TYPE_HRTIME: 583 case DATA_TYPE_NVLIST: 584 case DATA_TYPE_NVLIST_ARRAY: 585 case DATA_TYPE_BOOLEAN: 586 case DATA_TYPE_UNKNOWN: 587 default: 588 /* 589 * unknown/unsupported data type 590 */ 591 return (-1); /* error fail match */ 592 } 593 594 /* 595 * check to see if sscanf failed conversion, return approximate 596 * pointer to problem 597 */ 598 if (sr != 1) { 599 if (ep) 600 *ep = value; 601 return (-1); /* error fail match - syntax */ 602 } 603 604 return (0); /* fail match */ 605 } 606 607 int 608 nvpair_value_match(nvpair_t *nvp, int ai, char *value, char **ep) 609 { 610 return (nvpair_value_match_regex(nvp, ai, value, NULL, ep)); 611 } 612