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