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