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 (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <unistd.h> 26 #include <strings.h> 27 #include <libintl.h> 28 #include <sys/types.h> 29 #include <sys/inttypes.h> 30 #include <stdarg.h> 31 #include <note.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 /* 43 * Print control structure. 44 */ 45 46 #define DEFINEOP(opname, vtype) \ 47 struct { \ 48 int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \ 49 const char *, vtype); \ 50 void *arg; \ 51 } opname 52 53 #define DEFINEARROP(opname, vtype) \ 54 struct { \ 55 int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \ 56 const char *, vtype, uint_t); \ 57 void *arg; \ 58 } opname 59 60 struct nvlist_printops { 61 DEFINEOP(print_boolean, int); 62 DEFINEOP(print_boolean_value, boolean_t); 63 DEFINEOP(print_byte, uchar_t); 64 DEFINEOP(print_int8, int8_t); 65 DEFINEOP(print_uint8, uint8_t); 66 DEFINEOP(print_int16, int16_t); 67 DEFINEOP(print_uint16, uint16_t); 68 DEFINEOP(print_int32, int32_t); 69 DEFINEOP(print_uint32, uint32_t); 70 DEFINEOP(print_int64, int64_t); 71 DEFINEOP(print_uint64, uint64_t); 72 DEFINEOP(print_double, double); 73 DEFINEOP(print_string, char *); 74 DEFINEOP(print_hrtime, hrtime_t); 75 DEFINEOP(print_nvlist, nvlist_t *); 76 DEFINEARROP(print_boolean_array, boolean_t *); 77 DEFINEARROP(print_byte_array, uchar_t *); 78 DEFINEARROP(print_int8_array, int8_t *); 79 DEFINEARROP(print_uint8_array, uint8_t *); 80 DEFINEARROP(print_int16_array, int16_t *); 81 DEFINEARROP(print_uint16_array, uint16_t *); 82 DEFINEARROP(print_int32_array, int32_t *); 83 DEFINEARROP(print_uint32_array, uint32_t *); 84 DEFINEARROP(print_int64_array, int64_t *); 85 DEFINEARROP(print_uint64_array, uint64_t *); 86 DEFINEARROP(print_string_array, char **); 87 DEFINEARROP(print_nvlist_array, nvlist_t **); 88 }; 89 90 struct nvlist_prtctl { 91 FILE *nvprt_fp; /* output destination */ 92 enum nvlist_indent_mode nvprt_indent_mode; /* see above */ 93 int nvprt_indent; /* absolute indent, or tab depth */ 94 int nvprt_indentinc; /* indent or tab increment */ 95 const char *nvprt_nmfmt; /* member name format, max one %s */ 96 const char *nvprt_eomfmt; /* after member format, e.g. "\n" */ 97 const char *nvprt_btwnarrfmt; /* between array members */ 98 int nvprt_btwnarrfmt_nl; /* nvprt_eoamfmt includes newline? */ 99 struct nvlist_printops *nvprt_dfltops; 100 struct nvlist_printops *nvprt_custops; 101 }; 102 103 #define DFLTPRTOP(pctl, type) \ 104 ((pctl)->nvprt_dfltops->print_##type.op) 105 106 #define DFLTPRTOPARG(pctl, type) \ 107 ((pctl)->nvprt_dfltops->print_##type.arg) 108 109 #define CUSTPRTOP(pctl, type) \ 110 ((pctl)->nvprt_custops->print_##type.op) 111 112 #define CUSTPRTOPARG(pctl, type) \ 113 ((pctl)->nvprt_custops->print_##type.arg) 114 115 #define RENDER(pctl, type, nvl, name, val) \ 116 { \ 117 int done = 0; \ 118 if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \ 119 done = CUSTPRTOP(pctl, type)(pctl, \ 120 CUSTPRTOPARG(pctl, type), nvl, name, val); \ 121 } \ 122 if (!done) { \ 123 (void) DFLTPRTOP(pctl, type)(pctl, \ 124 DFLTPRTOPARG(pctl, type), nvl, name, val); \ 125 } \ 126 (void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \ 127 } 128 129 #define ARENDER(pctl, type, nvl, name, arrp, count) \ 130 { \ 131 int done = 0; \ 132 if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \ 133 done = CUSTPRTOP(pctl, type)(pctl, \ 134 CUSTPRTOPARG(pctl, type), nvl, name, arrp, count); \ 135 } \ 136 if (!done) { \ 137 (void) DFLTPRTOP(pctl, type)(pctl, \ 138 DFLTPRTOPARG(pctl, type), nvl, name, arrp, count); \ 139 } \ 140 (void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \ 141 } 142 143 static void nvlist_print_with_indent(nvlist_t *, nvlist_prtctl_t); 144 145 /* 146 * ====================================================================== 147 * | | 148 * | Indentation | 149 * | | 150 * ====================================================================== 151 */ 152 153 static void 154 indent(nvlist_prtctl_t pctl, int onemore) 155 { 156 int depth; 157 158 switch (pctl->nvprt_indent_mode) { 159 case NVLIST_INDENT_ABS: 160 (void) fprintf(pctl->nvprt_fp, "%*s", 161 pctl->nvprt_indent + onemore * pctl->nvprt_indentinc, ""); 162 break; 163 164 case NVLIST_INDENT_TABBED: 165 depth = pctl->nvprt_indent + onemore; 166 while (depth-- > 0) 167 (void) fprintf(pctl->nvprt_fp, "\t"); 168 } 169 } 170 171 /* 172 * ====================================================================== 173 * | | 174 * | Default nvlist member rendering functions. | 175 * | | 176 * ====================================================================== 177 */ 178 179 /* 180 * Generate functions to print single-valued nvlist members. 181 * 182 * type_and_variant - suffix to form function name 183 * vtype - C type for the member value 184 * ptype - C type to cast value to for printing 185 * vfmt - format string for pair value, e.g "%d" or "0x%llx" 186 */ 187 188 #define NVLIST_PRTFUNC(type_and_variant, vtype, ptype, vfmt) \ 189 static int \ 190 nvprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \ 191 nvlist_t *nvl, const char *name, vtype value) \ 192 { \ 193 FILE *fp = pctl->nvprt_fp; \ 194 NOTE(ARGUNUSED(private)) \ 195 NOTE(ARGUNUSED(nvl)) \ 196 indent(pctl, 1); \ 197 (void) fprintf(fp, pctl->nvprt_nmfmt, name); \ 198 (void) fprintf(fp, vfmt, (ptype)value); \ 199 return (1); \ 200 } 201 202 NVLIST_PRTFUNC(boolean, int, int, "%d") 203 NVLIST_PRTFUNC(boolean_value, boolean_t, int, "%d") 204 NVLIST_PRTFUNC(byte, uchar_t, uchar_t, "0x%2.2x") 205 NVLIST_PRTFUNC(int8, int8_t, int, "%d") 206 NVLIST_PRTFUNC(uint8, uint8_t, uint8_t, "0x%x") 207 NVLIST_PRTFUNC(int16, int16_t, int16_t, "%d") 208 NVLIST_PRTFUNC(uint16, uint16_t, uint16_t, "0x%x") 209 NVLIST_PRTFUNC(int32, int32_t, int32_t, "%d") 210 NVLIST_PRTFUNC(uint32, uint32_t, uint32_t, "0x%x") 211 NVLIST_PRTFUNC(int64, int64_t, longlong_t, "%lld") 212 NVLIST_PRTFUNC(uint64, uint64_t, u_longlong_t, "0x%llx") 213 NVLIST_PRTFUNC(double, double, double, "0x%llf") 214 NVLIST_PRTFUNC(string, char *, char *, "%s") 215 NVLIST_PRTFUNC(hrtime, hrtime_t, hrtime_t, "0x%llx") 216 217 /* 218 * Generate functions to print array-valued nvlist members. 219 */ 220 221 #define NVLIST_ARRPRTFUNC(type_and_variant, vtype, ptype, vfmt) \ 222 static int \ 223 nvaprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \ 224 nvlist_t *nvl, const char *name, vtype *valuep, uint_t count) \ 225 { \ 226 FILE *fp = pctl->nvprt_fp; \ 227 uint_t i; \ 228 NOTE(ARGUNUSED(private)) \ 229 NOTE(ARGUNUSED(nvl)) \ 230 for (i = 0; i < count; i++) { \ 231 if (i == 0 || pctl->nvprt_btwnarrfmt_nl) { \ 232 indent(pctl, 1); \ 233 (void) fprintf(fp, pctl->nvprt_nmfmt, name); \ 234 if (pctl->nvprt_btwnarrfmt_nl) \ 235 (void) fprintf(fp, "[%d]: ", i); \ 236 } \ 237 if (i != 0) \ 238 (void) fprintf(fp, pctl->nvprt_btwnarrfmt); \ 239 (void) fprintf(fp, vfmt, (ptype)valuep[i]); \ 240 } \ 241 return (1); \ 242 } 243 244 NVLIST_ARRPRTFUNC(boolean_array, boolean_t, boolean_t, "%d") 245 NVLIST_ARRPRTFUNC(byte_array, uchar_t, uchar_t, "0x%2.2x") 246 NVLIST_ARRPRTFUNC(int8_array, int8_t, int8_t, "%d") 247 NVLIST_ARRPRTFUNC(uint8_array, uint8_t, uint8_t, "0x%x") 248 NVLIST_ARRPRTFUNC(int16_array, int16_t, int16_t, "%d") 249 NVLIST_ARRPRTFUNC(uint16_array, uint16_t, uint16_t, "0x%x") 250 NVLIST_ARRPRTFUNC(int32_array, int32_t, int32_t, "%d") 251 NVLIST_ARRPRTFUNC(uint32_array, uint32_t, uint32_t, "0x%x") 252 NVLIST_ARRPRTFUNC(int64_array, int64_t, longlong_t, "%lld") 253 NVLIST_ARRPRTFUNC(uint64_array, uint64_t, u_longlong_t, "0x%llx") 254 NVLIST_ARRPRTFUNC(string_array, char *, char *, "%s") 255 256 /*ARGSUSED*/ 257 static int 258 nvprint_nvlist(nvlist_prtctl_t pctl, void *private, 259 nvlist_t *nvl, const char *name, nvlist_t *value) 260 { 261 FILE *fp = pctl->nvprt_fp; 262 263 indent(pctl, 1); 264 (void) fprintf(fp, "%s = (embedded nvlist)\n", name); 265 266 pctl->nvprt_indent += pctl->nvprt_indentinc; 267 nvlist_print_with_indent(value, pctl); 268 pctl->nvprt_indent -= pctl->nvprt_indentinc; 269 270 indent(pctl, 1); 271 (void) fprintf(fp, "(end %s)\n", name); 272 273 return (1); 274 } 275 276 /*ARGSUSED*/ 277 static int 278 nvaprint_nvlist_array(nvlist_prtctl_t pctl, void *private, 279 nvlist_t *nvl, const char *name, nvlist_t **valuep, uint_t count) 280 { 281 FILE *fp = pctl->nvprt_fp; 282 uint_t i; 283 284 indent(pctl, 1); 285 (void) fprintf(fp, "%s = (array of embedded nvlists)\n", name); 286 287 for (i = 0; i < count; i++) { 288 indent(pctl, 1); 289 (void) fprintf(fp, "(start %s[%d])\n", name, i); 290 291 pctl->nvprt_indent += pctl->nvprt_indentinc; 292 nvlist_print_with_indent(valuep[i], pctl); 293 pctl->nvprt_indent -= pctl->nvprt_indentinc; 294 295 indent(pctl, 1); 296 (void) fprintf(fp, "(end %s[%d])\n", name, i); 297 } 298 299 return (1); 300 } 301 302 /* 303 * ====================================================================== 304 * | | 305 * | Interfaces that allow control over formatting. | 306 * | | 307 * ====================================================================== 308 */ 309 310 void 311 nvlist_prtctl_setdest(nvlist_prtctl_t pctl, FILE *fp) 312 { 313 pctl->nvprt_fp = fp; 314 } 315 316 FILE * 317 nvlist_prtctl_getdest(nvlist_prtctl_t pctl) 318 { 319 return (pctl->nvprt_fp); 320 } 321 322 323 void 324 nvlist_prtctl_setindent(nvlist_prtctl_t pctl, enum nvlist_indent_mode mode, 325 int start, int inc) 326 { 327 if (mode < NVLIST_INDENT_ABS || mode > NVLIST_INDENT_TABBED) 328 mode = NVLIST_INDENT_TABBED; 329 330 if (start < 0) 331 start = 0; 332 333 if (inc < 0) 334 inc = 1; 335 336 pctl->nvprt_indent_mode = mode; 337 pctl->nvprt_indent = start; 338 pctl->nvprt_indentinc = inc; 339 } 340 341 void 342 nvlist_prtctl_doindent(nvlist_prtctl_t pctl, int onemore) 343 { 344 indent(pctl, onemore); 345 } 346 347 348 void 349 nvlist_prtctl_setfmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which, 350 const char *fmt) 351 { 352 switch (which) { 353 case NVLIST_FMT_MEMBER_NAME: 354 if (fmt == NULL) 355 fmt = "%s = "; 356 pctl->nvprt_nmfmt = fmt; 357 break; 358 359 case NVLIST_FMT_MEMBER_POSTAMBLE: 360 if (fmt == NULL) 361 fmt = "\n"; 362 pctl->nvprt_eomfmt = fmt; 363 break; 364 365 case NVLIST_FMT_BTWN_ARRAY: 366 if (fmt == NULL) { 367 pctl->nvprt_btwnarrfmt = " "; 368 pctl->nvprt_btwnarrfmt_nl = 0; 369 } else { 370 pctl->nvprt_btwnarrfmt = fmt; 371 pctl->nvprt_btwnarrfmt_nl = (strstr(fmt, "\n") != NULL); 372 } 373 break; 374 375 default: 376 break; 377 } 378 } 379 380 381 void 382 nvlist_prtctl_dofmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which, ...) 383 { 384 FILE *fp = pctl->nvprt_fp; 385 va_list ap; 386 char *name; 387 388 va_start(ap, which); 389 390 switch (which) { 391 case NVLIST_FMT_MEMBER_NAME: 392 name = va_arg(ap, char *); 393 (void) fprintf(fp, pctl->nvprt_nmfmt, name); 394 break; 395 396 case NVLIST_FMT_MEMBER_POSTAMBLE: 397 (void) fprintf(fp, pctl->nvprt_eomfmt); 398 break; 399 400 case NVLIST_FMT_BTWN_ARRAY: 401 (void) fprintf(fp, pctl->nvprt_btwnarrfmt); \ 402 break; 403 404 default: 405 break; 406 } 407 408 va_end(ap); 409 } 410 411 /* 412 * ====================================================================== 413 * | | 414 * | Interfaces to allow appointment of replacement rendering functions.| 415 * | | 416 * ====================================================================== 417 */ 418 419 #define NVLIST_PRINTCTL_REPLACE(type, vtype) \ 420 void \ 421 nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \ 422 int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype), \ 423 void *private) \ 424 { \ 425 CUSTPRTOP(pctl, type) = func; \ 426 CUSTPRTOPARG(pctl, type) = private; \ 427 } 428 429 NVLIST_PRINTCTL_REPLACE(boolean, int) 430 NVLIST_PRINTCTL_REPLACE(boolean_value, boolean_t) 431 NVLIST_PRINTCTL_REPLACE(byte, uchar_t) 432 NVLIST_PRINTCTL_REPLACE(int8, int8_t) 433 NVLIST_PRINTCTL_REPLACE(uint8, uint8_t) 434 NVLIST_PRINTCTL_REPLACE(int16, int16_t) 435 NVLIST_PRINTCTL_REPLACE(uint16, uint16_t) 436 NVLIST_PRINTCTL_REPLACE(int32, int32_t) 437 NVLIST_PRINTCTL_REPLACE(uint32, uint32_t) 438 NVLIST_PRINTCTL_REPLACE(int64, int64_t) 439 NVLIST_PRINTCTL_REPLACE(uint64, uint64_t) 440 NVLIST_PRINTCTL_REPLACE(double, double) 441 NVLIST_PRINTCTL_REPLACE(string, char *) 442 NVLIST_PRINTCTL_REPLACE(hrtime, hrtime_t) 443 NVLIST_PRINTCTL_REPLACE(nvlist, nvlist_t *) 444 445 #define NVLIST_PRINTCTL_AREPLACE(type, vtype) \ 446 void \ 447 nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \ 448 int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, \ 449 uint_t), void *private) \ 450 { \ 451 CUSTPRTOP(pctl, type) = func; \ 452 CUSTPRTOPARG(pctl, type) = private; \ 453 } 454 455 NVLIST_PRINTCTL_AREPLACE(boolean_array, boolean_t *) 456 NVLIST_PRINTCTL_AREPLACE(byte_array, uchar_t *) 457 NVLIST_PRINTCTL_AREPLACE(int8_array, int8_t *) 458 NVLIST_PRINTCTL_AREPLACE(uint8_array, uint8_t *) 459 NVLIST_PRINTCTL_AREPLACE(int16_array, int16_t *) 460 NVLIST_PRINTCTL_AREPLACE(uint16_array, uint16_t *) 461 NVLIST_PRINTCTL_AREPLACE(int32_array, int32_t *) 462 NVLIST_PRINTCTL_AREPLACE(uint32_array, uint32_t *) 463 NVLIST_PRINTCTL_AREPLACE(int64_array, int64_t *) 464 NVLIST_PRINTCTL_AREPLACE(uint64_array, uint64_t *) 465 NVLIST_PRINTCTL_AREPLACE(string_array, char **) 466 NVLIST_PRINTCTL_AREPLACE(nvlist_array, nvlist_t **) 467 468 /* 469 * ====================================================================== 470 * | | 471 * | Interfaces to manage nvlist_prtctl_t cookies. | 472 * | | 473 * ====================================================================== 474 */ 475 476 477 static const struct nvlist_printops defprtops = { 478 { nvprint_boolean, NULL }, 479 { nvprint_boolean_value, NULL }, 480 { nvprint_byte, NULL }, 481 { nvprint_int8, NULL }, 482 { nvprint_uint8, NULL }, 483 { nvprint_int16, NULL }, 484 { nvprint_uint16, NULL }, 485 { nvprint_int32, NULL }, 486 { nvprint_uint32, NULL }, 487 { nvprint_int64, NULL }, 488 { nvprint_uint64, NULL }, 489 { nvprint_double, NULL }, 490 { nvprint_string, NULL }, 491 { nvprint_hrtime, NULL }, 492 { nvprint_nvlist, NULL }, 493 { nvaprint_boolean_array, NULL }, 494 { nvaprint_byte_array, NULL }, 495 { nvaprint_int8_array, NULL }, 496 { nvaprint_uint8_array, NULL }, 497 { nvaprint_int16_array, NULL }, 498 { nvaprint_uint16_array, NULL }, 499 { nvaprint_int32_array, NULL }, 500 { nvaprint_uint32_array, NULL }, 501 { nvaprint_int64_array, NULL }, 502 { nvaprint_uint64_array, NULL }, 503 { nvaprint_string_array, NULL }, 504 { nvaprint_nvlist_array, NULL }, 505 }; 506 507 static void 508 prtctl_defaults(FILE *fp, struct nvlist_prtctl *pctl, 509 struct nvlist_printops *ops) 510 { 511 pctl->nvprt_fp = fp; 512 pctl->nvprt_indent_mode = NVLIST_INDENT_TABBED; 513 pctl->nvprt_indent = 0; 514 pctl->nvprt_indentinc = 1; 515 pctl->nvprt_nmfmt = "%s = "; 516 pctl->nvprt_eomfmt = "\n"; 517 pctl->nvprt_btwnarrfmt = " "; 518 pctl->nvprt_btwnarrfmt_nl = 0; 519 520 pctl->nvprt_dfltops = (struct nvlist_printops *)&defprtops; 521 pctl->nvprt_custops = ops; 522 } 523 524 nvlist_prtctl_t 525 nvlist_prtctl_alloc(void) 526 { 527 struct nvlist_prtctl *pctl; 528 struct nvlist_printops *ops; 529 530 if ((pctl = malloc(sizeof (*pctl))) == NULL) 531 return (NULL); 532 533 if ((ops = calloc(1, sizeof (*ops))) == NULL) { 534 free(pctl); 535 return (NULL); 536 } 537 538 prtctl_defaults(stdout, pctl, ops); 539 540 return (pctl); 541 } 542 543 void 544 nvlist_prtctl_free(nvlist_prtctl_t pctl) 545 { 546 if (pctl != NULL) { 547 free(pctl->nvprt_custops); 548 free(pctl); 549 } 550 } 551 552 /* 553 * ====================================================================== 554 * | | 555 * | Top-level print request interfaces. | 556 * | | 557 * ====================================================================== 558 */ 559 560 /* 561 * nvlist_print - Prints elements in an event buffer 562 */ 563 static void 564 nvlist_print_with_indent(nvlist_t *nvl, nvlist_prtctl_t pctl) 565 { 566 FILE *fp = pctl->nvprt_fp; 567 char *name; 568 uint_t nelem; 569 nvpair_t *nvp; 570 571 if (nvl == NULL) 572 return; 573 574 indent(pctl, 0); 575 (void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl)); 576 577 nvp = nvlist_next_nvpair(nvl, NULL); 578 579 while (nvp) { 580 data_type_t type = nvpair_type(nvp); 581 582 name = nvpair_name(nvp); 583 nelem = 0; 584 585 switch (type) { 586 case DATA_TYPE_BOOLEAN: { 587 RENDER(pctl, boolean, nvl, name, 1); 588 break; 589 } 590 case DATA_TYPE_BOOLEAN_VALUE: { 591 boolean_t val; 592 (void) nvpair_value_boolean_value(nvp, &val); 593 RENDER(pctl, boolean_value, nvl, name, val); 594 break; 595 } 596 case DATA_TYPE_BYTE: { 597 uchar_t val; 598 (void) nvpair_value_byte(nvp, &val); 599 RENDER(pctl, byte, nvl, name, val); 600 break; 601 } 602 case DATA_TYPE_INT8: { 603 int8_t val; 604 (void) nvpair_value_int8(nvp, &val); 605 RENDER(pctl, int8, nvl, name, val); 606 break; 607 } 608 case DATA_TYPE_UINT8: { 609 uint8_t val; 610 (void) nvpair_value_uint8(nvp, &val); 611 RENDER(pctl, uint8, nvl, name, val); 612 break; 613 } 614 case DATA_TYPE_INT16: { 615 int16_t val; 616 (void) nvpair_value_int16(nvp, &val); 617 RENDER(pctl, int16, nvl, name, val); 618 break; 619 } 620 case DATA_TYPE_UINT16: { 621 uint16_t val; 622 (void) nvpair_value_uint16(nvp, &val); 623 RENDER(pctl, uint16, nvl, name, val); 624 break; 625 } 626 case DATA_TYPE_INT32: { 627 int32_t val; 628 (void) nvpair_value_int32(nvp, &val); 629 RENDER(pctl, int32, nvl, name, val); 630 break; 631 } 632 case DATA_TYPE_UINT32: { 633 uint32_t val; 634 (void) nvpair_value_uint32(nvp, &val); 635 RENDER(pctl, uint32, nvl, name, val); 636 break; 637 } 638 case DATA_TYPE_INT64: { 639 int64_t val; 640 (void) nvpair_value_int64(nvp, &val); 641 RENDER(pctl, int64, nvl, name, val); 642 break; 643 } 644 case DATA_TYPE_UINT64: { 645 uint64_t val; 646 (void) nvpair_value_uint64(nvp, &val); 647 RENDER(pctl, uint64, nvl, name, val); 648 break; 649 } 650 case DATA_TYPE_DOUBLE: { 651 double val; 652 (void) nvpair_value_double(nvp, &val); 653 RENDER(pctl, double, nvl, name, val); 654 break; 655 } 656 case DATA_TYPE_STRING: { 657 char *val; 658 (void) nvpair_value_string(nvp, &val); 659 RENDER(pctl, string, nvl, name, val); 660 break; 661 } 662 case DATA_TYPE_BOOLEAN_ARRAY: { 663 boolean_t *val; 664 (void) nvpair_value_boolean_array(nvp, &val, &nelem); 665 ARENDER(pctl, boolean_array, nvl, name, val, nelem); 666 break; 667 } 668 case DATA_TYPE_BYTE_ARRAY: { 669 uchar_t *val; 670 (void) nvpair_value_byte_array(nvp, &val, &nelem); 671 ARENDER(pctl, byte_array, nvl, name, val, nelem); 672 break; 673 } 674 case DATA_TYPE_INT8_ARRAY: { 675 int8_t *val; 676 (void) nvpair_value_int8_array(nvp, &val, &nelem); 677 ARENDER(pctl, int8_array, nvl, name, val, nelem); 678 break; 679 } 680 case DATA_TYPE_UINT8_ARRAY: { 681 uint8_t *val; 682 (void) nvpair_value_uint8_array(nvp, &val, &nelem); 683 ARENDER(pctl, uint8_array, nvl, name, val, nelem); 684 break; 685 } 686 case DATA_TYPE_INT16_ARRAY: { 687 int16_t *val; 688 (void) nvpair_value_int16_array(nvp, &val, &nelem); 689 ARENDER(pctl, int16_array, nvl, name, val, nelem); 690 break; 691 } 692 case DATA_TYPE_UINT16_ARRAY: { 693 uint16_t *val; 694 (void) nvpair_value_uint16_array(nvp, &val, &nelem); 695 ARENDER(pctl, uint16_array, nvl, name, val, nelem); 696 break; 697 } 698 case DATA_TYPE_INT32_ARRAY: { 699 int32_t *val; 700 (void) nvpair_value_int32_array(nvp, &val, &nelem); 701 ARENDER(pctl, int32_array, nvl, name, val, nelem); 702 break; 703 } 704 case DATA_TYPE_UINT32_ARRAY: { 705 uint32_t *val; 706 (void) nvpair_value_uint32_array(nvp, &val, &nelem); 707 ARENDER(pctl, uint32_array, nvl, name, val, nelem); 708 break; 709 } 710 case DATA_TYPE_INT64_ARRAY: { 711 int64_t *val; 712 (void) nvpair_value_int64_array(nvp, &val, &nelem); 713 ARENDER(pctl, int64_array, nvl, name, val, nelem); 714 break; 715 } 716 case DATA_TYPE_UINT64_ARRAY: { 717 uint64_t *val; 718 (void) nvpair_value_uint64_array(nvp, &val, &nelem); 719 ARENDER(pctl, uint64_array, nvl, name, val, nelem); 720 break; 721 } 722 case DATA_TYPE_STRING_ARRAY: { 723 char **val; 724 (void) nvpair_value_string_array(nvp, &val, &nelem); 725 ARENDER(pctl, string_array, nvl, name, val, nelem); 726 break; 727 } 728 case DATA_TYPE_HRTIME: { 729 hrtime_t val; 730 (void) nvpair_value_hrtime(nvp, &val); 731 RENDER(pctl, hrtime, nvl, name, val); 732 break; 733 } 734 case DATA_TYPE_NVLIST: { 735 nvlist_t *val; 736 (void) nvpair_value_nvlist(nvp, &val); 737 RENDER(pctl, nvlist, nvl, name, val); 738 break; 739 } 740 case DATA_TYPE_NVLIST_ARRAY: { 741 nvlist_t **val; 742 (void) nvpair_value_nvlist_array(nvp, &val, &nelem); 743 ARENDER(pctl, nvlist_array, nvl, name, val, nelem); 744 break; 745 } 746 default: 747 (void) fprintf(fp, " unknown data type (%d)", type); 748 break; 749 } 750 nvp = nvlist_next_nvpair(nvl, nvp); 751 } 752 } 753 754 void 755 nvlist_print(FILE *fp, nvlist_t *nvl) 756 { 757 struct nvlist_prtctl pc; 758 759 prtctl_defaults(fp, &pc, NULL); 760 nvlist_print_with_indent(nvl, &pc); 761 } 762 763 void 764 nvlist_prt(nvlist_t *nvl, nvlist_prtctl_t pctl) 765 { 766 nvlist_print_with_indent(nvl, pctl); 767 } 768 769 #define NVP(elem, type, vtype, ptype, format) { \ 770 vtype value; \ 771 \ 772 (void) nvpair_value_##type(elem, &value); \ 773 (void) printf("%*s%s: " format "\n", indent, "", \ 774 nvpair_name(elem), (ptype)value); \ 775 } 776 777 #define NVPA(elem, type, vtype, ptype, format) { \ 778 uint_t i, count; \ 779 vtype *value; \ 780 \ 781 (void) nvpair_value_##type(elem, &value, &count); \ 782 for (i = 0; i < count; i++) { \ 783 (void) printf("%*s%s[%d]: " format "\n", indent, "", \ 784 nvpair_name(elem), i, (ptype)value[i]); \ 785 } \ 786 } 787 788 /* 789 * Similar to nvlist_print() but handles arrays slightly differently. 790 */ 791 void 792 dump_nvlist(nvlist_t *list, int indent) 793 { 794 nvpair_t *elem = NULL; 795 boolean_t bool_value; 796 nvlist_t *nvlist_value; 797 nvlist_t **nvlist_array_value; 798 uint_t i, count; 799 800 if (list == NULL) { 801 return; 802 } 803 804 while ((elem = nvlist_next_nvpair(list, elem)) != NULL) { 805 switch (nvpair_type(elem)) { 806 case DATA_TYPE_BOOLEAN_VALUE: 807 (void) nvpair_value_boolean_value(elem, &bool_value); 808 (void) printf("%*s%s: %s\n", indent, "", 809 nvpair_name(elem), bool_value ? "true" : "false"); 810 break; 811 812 case DATA_TYPE_BYTE: 813 NVP(elem, byte, uchar_t, int, "%u"); 814 break; 815 816 case DATA_TYPE_INT8: 817 NVP(elem, int8, int8_t, int, "%d"); 818 break; 819 820 case DATA_TYPE_UINT8: 821 NVP(elem, uint8, uint8_t, int, "%u"); 822 break; 823 824 case DATA_TYPE_INT16: 825 NVP(elem, int16, int16_t, int, "%d"); 826 break; 827 828 case DATA_TYPE_UINT16: 829 NVP(elem, uint16, uint16_t, int, "%u"); 830 break; 831 832 case DATA_TYPE_INT32: 833 NVP(elem, int32, int32_t, long, "%ld"); 834 break; 835 836 case DATA_TYPE_UINT32: 837 NVP(elem, uint32, uint32_t, ulong_t, "%lu"); 838 break; 839 840 case DATA_TYPE_INT64: 841 NVP(elem, int64, int64_t, longlong_t, "%lld"); 842 break; 843 844 case DATA_TYPE_UINT64: 845 NVP(elem, uint64, uint64_t, u_longlong_t, "%llu"); 846 break; 847 848 case DATA_TYPE_STRING: 849 NVP(elem, string, char *, char *, "'%s'"); 850 break; 851 852 case DATA_TYPE_BYTE_ARRAY: 853 NVPA(elem, byte_array, uchar_t, int, "%u"); 854 break; 855 856 case DATA_TYPE_INT8_ARRAY: 857 NVPA(elem, int8_array, int8_t, int, "%d"); 858 break; 859 860 case DATA_TYPE_UINT8_ARRAY: 861 NVPA(elem, uint8_array, uint8_t, int, "%u"); 862 break; 863 864 case DATA_TYPE_INT16_ARRAY: 865 NVPA(elem, int16_array, int16_t, int, "%d"); 866 break; 867 868 case DATA_TYPE_UINT16_ARRAY: 869 NVPA(elem, uint16_array, uint16_t, int, "%u"); 870 break; 871 872 case DATA_TYPE_INT32_ARRAY: 873 NVPA(elem, int32_array, int32_t, long, "%ld"); 874 break; 875 876 case DATA_TYPE_UINT32_ARRAY: 877 NVPA(elem, uint32_array, uint32_t, ulong_t, "%lu"); 878 break; 879 880 case DATA_TYPE_INT64_ARRAY: 881 NVPA(elem, int64_array, int64_t, longlong_t, "%lld"); 882 break; 883 884 case DATA_TYPE_UINT64_ARRAY: 885 NVPA(elem, uint64_array, uint64_t, u_longlong_t, 886 "%llu"); 887 break; 888 889 case DATA_TYPE_STRING_ARRAY: 890 NVPA(elem, string_array, char *, char *, "'%s'"); 891 break; 892 893 case DATA_TYPE_NVLIST: 894 (void) nvpair_value_nvlist(elem, &nvlist_value); 895 (void) printf("%*s%s:\n", indent, "", 896 nvpair_name(elem)); 897 dump_nvlist(nvlist_value, indent + 4); 898 break; 899 900 case DATA_TYPE_NVLIST_ARRAY: 901 (void) nvpair_value_nvlist_array(elem, 902 &nvlist_array_value, &count); 903 for (i = 0; i < count; i++) { 904 (void) printf("%*s%s[%u]:\n", indent, "", 905 nvpair_name(elem), i); 906 dump_nvlist(nvlist_array_value[i], indent + 4); 907 } 908 break; 909 910 default: 911 (void) printf(dgettext(TEXT_DOMAIN, "bad config type " 912 "%d for %s\n"), nvpair_type(elem), 913 nvpair_name(elem)); 914 } 915 } 916 } 917 918 /* 919 * ====================================================================== 920 * | | 921 * | Misc private interface. | 922 * | | 923 * ====================================================================== 924 */ 925 926 /* 927 * Determine if string 'value' matches 'nvp' value. The 'value' string is 928 * converted, depending on the type of 'nvp', prior to match. For numeric 929 * types, a radix independent sscanf conversion of 'value' is used. If 'nvp' 930 * is an array type, 'ai' is the index into the array against which we are 931 * checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass 932 * in a regex_t compilation of value in 'value_regex' to trigger regular 933 * expression string match instead of simple strcmp(). 934 * 935 * Return 1 on match, 0 on no-match, and -1 on error. If the error is 936 * related to value syntax error and 'ep' is non-NULL, *ep will point into 937 * the 'value' string at the location where the error exists. 938 * 939 * NOTE: It may be possible to move the non-regex_t version of this into 940 * common code used by library/kernel/boot. 941 */ 942 int 943 nvpair_value_match_regex(nvpair_t *nvp, int ai, 944 char *value, regex_t *value_regex, char **ep) 945 { 946 char *evalue; 947 uint_t a_len; 948 int sr; 949 950 if (ep) 951 *ep = NULL; 952 953 if ((nvp == NULL) || (value == NULL)) 954 return (-1); /* error fail match - invalid args */ 955 956 /* make sure array and index combination make sense */ 957 if ((nvpair_type_is_array(nvp) && (ai < 0)) || 958 (!nvpair_type_is_array(nvp) && (ai >= 0))) 959 return (-1); /* error fail match - bad index */ 960 961 /* non-string values should be single 'chunk' */ 962 if ((nvpair_type(nvp) != DATA_TYPE_STRING) && 963 (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) { 964 value += strspn(value, " \t"); 965 evalue = value + strcspn(value, " \t"); 966 if (*evalue) { 967 if (ep) 968 *ep = evalue; 969 return (-1); /* error fail match - syntax */ 970 } 971 } 972 973 sr = EOF; 974 switch (nvpair_type(nvp)) { 975 case DATA_TYPE_STRING: { 976 char *val; 977 978 /* check string value for match */ 979 if (nvpair_value_string(nvp, &val) == 0) { 980 if (value_regex) { 981 if (regexec(value_regex, val, 982 (size_t)0, NULL, 0) == 0) 983 return (1); /* match */ 984 } else { 985 if (strcmp(value, val) == 0) 986 return (1); /* match */ 987 } 988 } 989 break; 990 } 991 case DATA_TYPE_STRING_ARRAY: { 992 char **val_array; 993 994 /* check indexed string value of array for match */ 995 if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) && 996 (ai < a_len)) { 997 if (value_regex) { 998 if (regexec(value_regex, val_array[ai], 999 (size_t)0, NULL, 0) == 0) 1000 return (1); 1001 } else { 1002 if (strcmp(value, val_array[ai]) == 0) 1003 return (1); 1004 } 1005 } 1006 break; 1007 } 1008 case DATA_TYPE_BYTE: { 1009 uchar_t val, val_arg; 1010 1011 /* scanf uchar_t from value and check for match */ 1012 sr = sscanf(value, "%c", &val_arg); 1013 if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) && 1014 (val == val_arg)) 1015 return (1); 1016 break; 1017 } 1018 case DATA_TYPE_BYTE_ARRAY: { 1019 uchar_t *val_array, val_arg; 1020 1021 1022 /* check indexed value of array for match */ 1023 sr = sscanf(value, "%c", &val_arg); 1024 if ((sr == 1) && 1025 (nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) && 1026 (ai < a_len) && 1027 (val_array[ai] == val_arg)) 1028 return (1); 1029 break; 1030 } 1031 case DATA_TYPE_INT8: { 1032 int8_t val, val_arg; 1033 1034 /* scanf int8_t from value and check for match */ 1035 sr = sscanf(value, "%"SCNi8, &val_arg); 1036 if ((sr == 1) && 1037 (nvpair_value_int8(nvp, &val) == 0) && 1038 (val == val_arg)) 1039 return (1); 1040 break; 1041 } 1042 case DATA_TYPE_INT8_ARRAY: { 1043 int8_t *val_array, val_arg; 1044 1045 /* check indexed value of array for match */ 1046 sr = sscanf(value, "%"SCNi8, &val_arg); 1047 if ((sr == 1) && 1048 (nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) && 1049 (ai < a_len) && 1050 (val_array[ai] == val_arg)) 1051 return (1); 1052 break; 1053 } 1054 case DATA_TYPE_UINT8: { 1055 uint8_t val, val_arg; 1056 1057 /* scanf uint8_t from value and check for match */ 1058 sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg); 1059 if ((sr == 1) && 1060 (nvpair_value_uint8(nvp, &val) == 0) && 1061 (val == val_arg)) 1062 return (1); 1063 break; 1064 } 1065 case DATA_TYPE_UINT8_ARRAY: { 1066 uint8_t *val_array, val_arg; 1067 1068 /* check indexed value of array for match */ 1069 sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg); 1070 if ((sr == 1) && 1071 (nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) && 1072 (ai < a_len) && 1073 (val_array[ai] == val_arg)) 1074 return (1); 1075 break; 1076 } 1077 case DATA_TYPE_INT16: { 1078 int16_t val, val_arg; 1079 1080 /* scanf int16_t from value and check for match */ 1081 sr = sscanf(value, "%"SCNi16, &val_arg); 1082 if ((sr == 1) && 1083 (nvpair_value_int16(nvp, &val) == 0) && 1084 (val == val_arg)) 1085 return (1); 1086 break; 1087 } 1088 case DATA_TYPE_INT16_ARRAY: { 1089 int16_t *val_array, val_arg; 1090 1091 /* check indexed value of array for match */ 1092 sr = sscanf(value, "%"SCNi16, &val_arg); 1093 if ((sr == 1) && 1094 (nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) && 1095 (ai < a_len) && 1096 (val_array[ai] == val_arg)) 1097 return (1); 1098 break; 1099 } 1100 case DATA_TYPE_UINT16: { 1101 uint16_t val, val_arg; 1102 1103 /* scanf uint16_t from value and check for match */ 1104 sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg); 1105 if ((sr == 1) && 1106 (nvpair_value_uint16(nvp, &val) == 0) && 1107 (val == val_arg)) 1108 return (1); 1109 break; 1110 } 1111 case DATA_TYPE_UINT16_ARRAY: { 1112 uint16_t *val_array, val_arg; 1113 1114 /* check indexed value of array for match */ 1115 sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg); 1116 if ((sr == 1) && 1117 (nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) && 1118 (ai < a_len) && 1119 (val_array[ai] == val_arg)) 1120 return (1); 1121 break; 1122 } 1123 case DATA_TYPE_INT32: { 1124 int32_t val, val_arg; 1125 1126 /* scanf int32_t from value and check for match */ 1127 sr = sscanf(value, "%"SCNi32, &val_arg); 1128 if ((sr == 1) && 1129 (nvpair_value_int32(nvp, &val) == 0) && 1130 (val == val_arg)) 1131 return (1); 1132 break; 1133 } 1134 case DATA_TYPE_INT32_ARRAY: { 1135 int32_t *val_array, val_arg; 1136 1137 /* check indexed value of array for match */ 1138 sr = sscanf(value, "%"SCNi32, &val_arg); 1139 if ((sr == 1) && 1140 (nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) && 1141 (ai < a_len) && 1142 (val_array[ai] == val_arg)) 1143 return (1); 1144 break; 1145 } 1146 case DATA_TYPE_UINT32: { 1147 uint32_t val, val_arg; 1148 1149 /* scanf uint32_t from value and check for match */ 1150 sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg); 1151 if ((sr == 1) && 1152 (nvpair_value_uint32(nvp, &val) == 0) && 1153 (val == val_arg)) 1154 return (1); 1155 break; 1156 } 1157 case DATA_TYPE_UINT32_ARRAY: { 1158 uint32_t *val_array, val_arg; 1159 1160 /* check indexed value of array for match */ 1161 sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg); 1162 if ((sr == 1) && 1163 (nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) && 1164 (ai < a_len) && 1165 (val_array[ai] == val_arg)) 1166 return (1); 1167 break; 1168 } 1169 case DATA_TYPE_INT64: { 1170 int64_t val, val_arg; 1171 1172 /* scanf int64_t from value and check for match */ 1173 sr = sscanf(value, "%"SCNi64, &val_arg); 1174 if ((sr == 1) && 1175 (nvpair_value_int64(nvp, &val) == 0) && 1176 (val == val_arg)) 1177 return (1); 1178 break; 1179 } 1180 case DATA_TYPE_INT64_ARRAY: { 1181 int64_t *val_array, val_arg; 1182 1183 /* check indexed value of array for match */ 1184 sr = sscanf(value, "%"SCNi64, &val_arg); 1185 if ((sr == 1) && 1186 (nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) && 1187 (ai < a_len) && 1188 (val_array[ai] == val_arg)) 1189 return (1); 1190 break; 1191 } 1192 case DATA_TYPE_UINT64: { 1193 uint64_t val_arg, val; 1194 1195 /* scanf uint64_t from value and check for match */ 1196 sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg); 1197 if ((sr == 1) && 1198 (nvpair_value_uint64(nvp, &val) == 0) && 1199 (val == val_arg)) 1200 return (1); 1201 break; 1202 } 1203 case DATA_TYPE_UINT64_ARRAY: { 1204 uint64_t *val_array, val_arg; 1205 1206 /* check indexed value of array for match */ 1207 sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg); 1208 if ((sr == 1) && 1209 (nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) && 1210 (ai < a_len) && 1211 (val_array[ai] == val_arg)) 1212 return (1); 1213 break; 1214 } 1215 case DATA_TYPE_BOOLEAN_VALUE: { 1216 boolean_t val, val_arg; 1217 1218 /* scanf boolean_t from value and check for match */ 1219 sr = sscanf(value, "%"SCNi32, &val_arg); 1220 if ((sr == 1) && 1221 (nvpair_value_boolean_value(nvp, &val) == 0) && 1222 (val == val_arg)) 1223 return (1); 1224 break; 1225 } 1226 case DATA_TYPE_BOOLEAN_ARRAY: { 1227 boolean_t *val_array, val_arg; 1228 1229 /* check indexed value of array for match */ 1230 sr = sscanf(value, "%"SCNi32, &val_arg); 1231 if ((sr == 1) && 1232 (nvpair_value_boolean_array(nvp, 1233 &val_array, &a_len) == 0) && 1234 (ai < a_len) && 1235 (val_array[ai] == val_arg)) 1236 return (1); 1237 break; 1238 } 1239 case DATA_TYPE_HRTIME: 1240 case DATA_TYPE_NVLIST: 1241 case DATA_TYPE_NVLIST_ARRAY: 1242 case DATA_TYPE_BOOLEAN: 1243 case DATA_TYPE_DOUBLE: 1244 case DATA_TYPE_UNKNOWN: 1245 default: 1246 /* 1247 * unknown/unsupported data type 1248 */ 1249 return (-1); /* error fail match */ 1250 } 1251 1252 /* 1253 * check to see if sscanf failed conversion, return approximate 1254 * pointer to problem 1255 */ 1256 if (sr != 1) { 1257 if (ep) 1258 *ep = value; 1259 return (-1); /* error fail match - syntax */ 1260 } 1261 1262 return (0); /* fail match */ 1263 } 1264 1265 int 1266 nvpair_value_match(nvpair_t *nvp, int ai, char *value, char **ep) 1267 { 1268 return (nvpair_value_match_regex(nvp, ai, value, NULL, ep)); 1269 } 1270