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, 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, "%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 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%f") 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 (void) private; \ 227 (void) nvl; \ 228 FILE *fp = pctl->nvprt_fp; \ 229 uint_t i; \ 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, "%s", 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 static int 257 nvprint_nvlist(nvlist_prtctl_t pctl, void *private, 258 nvlist_t *nvl, const char *name, nvlist_t *value) 259 { 260 (void) private, (void) nvl; 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 static int 277 nvaprint_nvlist_array(nvlist_prtctl_t pctl, void *private, 278 nvlist_t *nvl, const char *name, nvlist_t **valuep, uint_t count) 279 { 280 (void) private, (void) nvl; 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, "%s", pctl->nvprt_eomfmt); 398 break; 399 400 case NVLIST_FMT_BTWN_ARRAY: 401 (void) fprintf(fp, "%s", 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 { 479 { nvprint_boolean, NULL }, 480 { nvprint_boolean_value, NULL }, 481 { nvprint_byte, NULL }, 482 { nvprint_int8, NULL }, 483 { nvprint_uint8, NULL }, 484 { nvprint_int16, NULL }, 485 { nvprint_uint16, NULL }, 486 { nvprint_int32, NULL }, 487 { nvprint_uint32, NULL }, 488 { nvprint_int64, NULL }, 489 { nvprint_uint64, NULL }, 490 { nvprint_double, NULL }, 491 { nvprint_string, NULL }, 492 { nvprint_hrtime, NULL }, 493 { nvprint_nvlist, NULL }, 494 { nvaprint_boolean_array, NULL }, 495 { nvaprint_byte_array, NULL }, 496 { nvaprint_int8_array, NULL }, 497 { nvaprint_uint8_array, NULL }, 498 { nvaprint_int16_array, NULL }, 499 { nvaprint_uint16_array, NULL }, 500 { nvaprint_int32_array, NULL }, 501 { nvaprint_uint32_array, NULL }, 502 { nvaprint_int64_array, NULL }, 503 { nvaprint_uint64_array, NULL }, 504 { nvaprint_string_array, NULL }, 505 { nvaprint_nvlist_array, NULL }, 506 }; 507 508 static void 509 prtctl_defaults(FILE *fp, struct nvlist_prtctl *pctl, 510 struct nvlist_printops *ops) 511 { 512 pctl->nvprt_fp = fp; 513 pctl->nvprt_indent_mode = NVLIST_INDENT_TABBED; 514 pctl->nvprt_indent = 0; 515 pctl->nvprt_indentinc = 1; 516 pctl->nvprt_nmfmt = "%s = "; 517 pctl->nvprt_eomfmt = "\n"; 518 pctl->nvprt_btwnarrfmt = " "; 519 pctl->nvprt_btwnarrfmt_nl = 0; 520 521 pctl->nvprt_dfltops = (struct nvlist_printops *)&defprtops; 522 pctl->nvprt_custops = ops; 523 } 524 525 nvlist_prtctl_t 526 nvlist_prtctl_alloc(void) 527 { 528 struct nvlist_prtctl *pctl; 529 struct nvlist_printops *ops; 530 531 if ((pctl = malloc(sizeof (*pctl))) == NULL) 532 return (NULL); 533 534 if ((ops = calloc(1, sizeof (*ops))) == NULL) { 535 free(pctl); 536 return (NULL); 537 } 538 539 prtctl_defaults(stdout, pctl, ops); 540 541 return (pctl); 542 } 543 544 void 545 nvlist_prtctl_free(nvlist_prtctl_t pctl) 546 { 547 if (pctl != NULL) { 548 free(pctl->nvprt_custops); 549 free(pctl); 550 } 551 } 552 553 /* 554 * ====================================================================== 555 * | | 556 * | Top-level print request interfaces. | 557 * | | 558 * ====================================================================== 559 */ 560 561 /* 562 * nvlist_print - Prints elements in an event buffer 563 */ 564 static void 565 nvlist_print_with_indent(nvlist_t *nvl, nvlist_prtctl_t pctl) 566 { 567 FILE *fp = pctl->nvprt_fp; 568 char *name; 569 uint_t nelem; 570 nvpair_t *nvp; 571 572 if (nvl == NULL) 573 return; 574 575 indent(pctl, 0); 576 (void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl)); 577 578 nvp = nvlist_next_nvpair(nvl, NULL); 579 580 while (nvp) { 581 data_type_t type = nvpair_type(nvp); 582 583 name = nvpair_name(nvp); 584 nelem = 0; 585 586 switch (type) { 587 case DATA_TYPE_BOOLEAN: { 588 RENDER(pctl, boolean, nvl, name, 1); 589 break; 590 } 591 case DATA_TYPE_BOOLEAN_VALUE: { 592 boolean_t val; 593 (void) nvpair_value_boolean_value(nvp, &val); 594 RENDER(pctl, boolean_value, nvl, name, val); 595 break; 596 } 597 case DATA_TYPE_BYTE: { 598 uchar_t val; 599 (void) nvpair_value_byte(nvp, &val); 600 RENDER(pctl, byte, nvl, name, val); 601 break; 602 } 603 case DATA_TYPE_INT8: { 604 int8_t val; 605 (void) nvpair_value_int8(nvp, &val); 606 RENDER(pctl, int8, nvl, name, val); 607 break; 608 } 609 case DATA_TYPE_UINT8: { 610 uint8_t val; 611 (void) nvpair_value_uint8(nvp, &val); 612 RENDER(pctl, uint8, nvl, name, val); 613 break; 614 } 615 case DATA_TYPE_INT16: { 616 int16_t val; 617 (void) nvpair_value_int16(nvp, &val); 618 RENDER(pctl, int16, nvl, name, val); 619 break; 620 } 621 case DATA_TYPE_UINT16: { 622 uint16_t val; 623 (void) nvpair_value_uint16(nvp, &val); 624 RENDER(pctl, uint16, nvl, name, val); 625 break; 626 } 627 case DATA_TYPE_INT32: { 628 int32_t val; 629 (void) nvpair_value_int32(nvp, &val); 630 RENDER(pctl, int32, nvl, name, val); 631 break; 632 } 633 case DATA_TYPE_UINT32: { 634 uint32_t val; 635 (void) nvpair_value_uint32(nvp, &val); 636 RENDER(pctl, uint32, nvl, name, val); 637 break; 638 } 639 case DATA_TYPE_INT64: { 640 int64_t val; 641 (void) nvpair_value_int64(nvp, &val); 642 RENDER(pctl, int64, nvl, name, val); 643 break; 644 } 645 case DATA_TYPE_UINT64: { 646 uint64_t val; 647 (void) nvpair_value_uint64(nvp, &val); 648 RENDER(pctl, uint64, nvl, name, val); 649 break; 650 } 651 case DATA_TYPE_DOUBLE: { 652 double val; 653 (void) nvpair_value_double(nvp, &val); 654 RENDER(pctl, double, nvl, name, val); 655 break; 656 } 657 case DATA_TYPE_STRING: { 658 char *val; 659 (void) nvpair_value_string(nvp, &val); 660 RENDER(pctl, string, nvl, name, val); 661 break; 662 } 663 case DATA_TYPE_BOOLEAN_ARRAY: { 664 boolean_t *val; 665 (void) nvpair_value_boolean_array(nvp, &val, &nelem); 666 ARENDER(pctl, boolean_array, nvl, name, val, nelem); 667 break; 668 } 669 case DATA_TYPE_BYTE_ARRAY: { 670 uchar_t *val; 671 (void) nvpair_value_byte_array(nvp, &val, &nelem); 672 ARENDER(pctl, byte_array, nvl, name, val, nelem); 673 break; 674 } 675 case DATA_TYPE_INT8_ARRAY: { 676 int8_t *val; 677 (void) nvpair_value_int8_array(nvp, &val, &nelem); 678 ARENDER(pctl, int8_array, nvl, name, val, nelem); 679 break; 680 } 681 case DATA_TYPE_UINT8_ARRAY: { 682 uint8_t *val; 683 (void) nvpair_value_uint8_array(nvp, &val, &nelem); 684 ARENDER(pctl, uint8_array, nvl, name, val, nelem); 685 break; 686 } 687 case DATA_TYPE_INT16_ARRAY: { 688 int16_t *val; 689 (void) nvpair_value_int16_array(nvp, &val, &nelem); 690 ARENDER(pctl, int16_array, nvl, name, val, nelem); 691 break; 692 } 693 case DATA_TYPE_UINT16_ARRAY: { 694 uint16_t *val; 695 (void) nvpair_value_uint16_array(nvp, &val, &nelem); 696 ARENDER(pctl, uint16_array, nvl, name, val, nelem); 697 break; 698 } 699 case DATA_TYPE_INT32_ARRAY: { 700 int32_t *val; 701 (void) nvpair_value_int32_array(nvp, &val, &nelem); 702 ARENDER(pctl, int32_array, nvl, name, val, nelem); 703 break; 704 } 705 case DATA_TYPE_UINT32_ARRAY: { 706 uint32_t *val; 707 (void) nvpair_value_uint32_array(nvp, &val, &nelem); 708 ARENDER(pctl, uint32_array, nvl, name, val, nelem); 709 break; 710 } 711 case DATA_TYPE_INT64_ARRAY: { 712 int64_t *val; 713 (void) nvpair_value_int64_array(nvp, &val, &nelem); 714 ARENDER(pctl, int64_array, nvl, name, val, nelem); 715 break; 716 } 717 case DATA_TYPE_UINT64_ARRAY: { 718 uint64_t *val; 719 (void) nvpair_value_uint64_array(nvp, &val, &nelem); 720 ARENDER(pctl, uint64_array, nvl, name, val, nelem); 721 break; 722 } 723 case DATA_TYPE_STRING_ARRAY: { 724 char **val; 725 (void) nvpair_value_string_array(nvp, &val, &nelem); 726 ARENDER(pctl, string_array, nvl, name, val, nelem); 727 break; 728 } 729 case DATA_TYPE_HRTIME: { 730 hrtime_t val; 731 (void) nvpair_value_hrtime(nvp, &val); 732 RENDER(pctl, hrtime, nvl, name, val); 733 break; 734 } 735 case DATA_TYPE_NVLIST: { 736 nvlist_t *val; 737 (void) nvpair_value_nvlist(nvp, &val); 738 RENDER(pctl, nvlist, nvl, name, val); 739 break; 740 } 741 case DATA_TYPE_NVLIST_ARRAY: { 742 nvlist_t **val; 743 (void) nvpair_value_nvlist_array(nvp, &val, &nelem); 744 ARENDER(pctl, nvlist_array, nvl, name, val, nelem); 745 break; 746 } 747 default: 748 (void) fprintf(fp, " unknown data type (%d)", type); 749 break; 750 } 751 nvp = nvlist_next_nvpair(nvl, nvp); 752 } 753 } 754 755 void 756 nvlist_print(FILE *fp, nvlist_t *nvl) 757 { 758 struct nvlist_prtctl pc; 759 760 prtctl_defaults(fp, &pc, NULL); 761 nvlist_print_with_indent(nvl, &pc); 762 } 763 764 void 765 nvlist_prt(nvlist_t *nvl, nvlist_prtctl_t pctl) 766 { 767 nvlist_print_with_indent(nvl, pctl); 768 } 769 770 #define NVP(elem, type, vtype, ptype, format) { \ 771 vtype value; \ 772 \ 773 (void) nvpair_value_##type(elem, &value); \ 774 (void) printf("%*s%s: " format "\n", indent, "", \ 775 nvpair_name(elem), (ptype)value); \ 776 } 777 778 #define NVPA(elem, type, vtype, ptype, format) { \ 779 uint_t i, count; \ 780 vtype *value; \ 781 \ 782 (void) nvpair_value_##type(elem, &value, &count); \ 783 for (i = 0; i < count; i++) { \ 784 (void) printf("%*s%s[%d]: " format "\n", indent, "", \ 785 nvpair_name(elem), i, (ptype)value[i]); \ 786 } \ 787 } 788 789 /* 790 * Similar to nvlist_print() but handles arrays slightly differently. 791 */ 792 void 793 dump_nvlist(nvlist_t *list, int indent) 794 { 795 nvpair_t *elem = NULL; 796 boolean_t bool_value; 797 nvlist_t *nvlist_value; 798 nvlist_t **nvlist_array_value; 799 uint_t i, count; 800 801 if (list == NULL) { 802 return; 803 } 804 805 while ((elem = nvlist_next_nvpair(list, elem)) != NULL) { 806 switch (nvpair_type(elem)) { 807 case DATA_TYPE_BOOLEAN: 808 (void) printf("%*s%s\n", indent, "", nvpair_name(elem)); 809 break; 810 811 case DATA_TYPE_BOOLEAN_VALUE: 812 (void) nvpair_value_boolean_value(elem, &bool_value); 813 (void) printf("%*s%s: %s\n", indent, "", 814 nvpair_name(elem), bool_value ? "true" : "false"); 815 break; 816 817 case DATA_TYPE_BYTE: 818 NVP(elem, byte, uchar_t, int, "%u"); 819 break; 820 821 case DATA_TYPE_INT8: 822 NVP(elem, int8, int8_t, int, "%d"); 823 break; 824 825 case DATA_TYPE_UINT8: 826 NVP(elem, uint8, uint8_t, int, "%u"); 827 break; 828 829 case DATA_TYPE_INT16: 830 NVP(elem, int16, int16_t, int, "%d"); 831 break; 832 833 case DATA_TYPE_UINT16: 834 NVP(elem, uint16, uint16_t, int, "%u"); 835 break; 836 837 case DATA_TYPE_INT32: 838 NVP(elem, int32, int32_t, long, "%ld"); 839 break; 840 841 case DATA_TYPE_UINT32: 842 NVP(elem, uint32, uint32_t, ulong_t, "%lu"); 843 break; 844 845 case DATA_TYPE_INT64: 846 NVP(elem, int64, int64_t, longlong_t, "%lld"); 847 break; 848 849 case DATA_TYPE_UINT64: 850 NVP(elem, uint64, uint64_t, u_longlong_t, "%llu"); 851 break; 852 853 case DATA_TYPE_STRING: 854 NVP(elem, string, char *, char *, "'%s'"); 855 break; 856 857 case DATA_TYPE_BYTE_ARRAY: 858 NVPA(elem, byte_array, uchar_t, int, "%u"); 859 break; 860 861 case DATA_TYPE_INT8_ARRAY: 862 NVPA(elem, int8_array, int8_t, int, "%d"); 863 break; 864 865 case DATA_TYPE_UINT8_ARRAY: 866 NVPA(elem, uint8_array, uint8_t, int, "%u"); 867 break; 868 869 case DATA_TYPE_INT16_ARRAY: 870 NVPA(elem, int16_array, int16_t, int, "%d"); 871 break; 872 873 case DATA_TYPE_UINT16_ARRAY: 874 NVPA(elem, uint16_array, uint16_t, int, "%u"); 875 break; 876 877 case DATA_TYPE_INT32_ARRAY: 878 NVPA(elem, int32_array, int32_t, long, "%ld"); 879 break; 880 881 case DATA_TYPE_UINT32_ARRAY: 882 NVPA(elem, uint32_array, uint32_t, ulong_t, "%lu"); 883 break; 884 885 case DATA_TYPE_INT64_ARRAY: 886 NVPA(elem, int64_array, int64_t, longlong_t, "%lld"); 887 break; 888 889 case DATA_TYPE_UINT64_ARRAY: 890 NVPA(elem, uint64_array, uint64_t, u_longlong_t, 891 "%llu"); 892 break; 893 894 case DATA_TYPE_STRING_ARRAY: 895 NVPA(elem, string_array, char *, char *, "'%s'"); 896 break; 897 898 case DATA_TYPE_NVLIST: 899 (void) nvpair_value_nvlist(elem, &nvlist_value); 900 (void) printf("%*s%s:\n", indent, "", 901 nvpair_name(elem)); 902 dump_nvlist(nvlist_value, indent + 4); 903 break; 904 905 case DATA_TYPE_NVLIST_ARRAY: 906 (void) nvpair_value_nvlist_array(elem, 907 &nvlist_array_value, &count); 908 for (i = 0; i < count; i++) { 909 (void) printf("%*s%s[%u]:\n", indent, "", 910 nvpair_name(elem), i); 911 dump_nvlist(nvlist_array_value[i], indent + 4); 912 } 913 break; 914 915 default: 916 (void) printf(dgettext(TEXT_DOMAIN, "bad config type " 917 "%d for %s\n"), nvpair_type(elem), 918 nvpair_name(elem)); 919 } 920 } 921 } 922 923 /* 924 * ====================================================================== 925 * | | 926 * | Misc private interface. | 927 * | | 928 * ====================================================================== 929 */ 930 931 /* 932 * Determine if string 'value' matches 'nvp' value. The 'value' string is 933 * converted, depending on the type of 'nvp', prior to match. For numeric 934 * types, a radix independent sscanf conversion of 'value' is used. If 'nvp' 935 * is an array type, 'ai' is the index into the array against which we are 936 * checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass 937 * in a regex_t compilation of value in 'value_regex' to trigger regular 938 * expression string match instead of simple strcmp(). 939 * 940 * Return 1 on match, 0 on no-match, and -1 on error. If the error is 941 * related to value syntax error and 'ep' is non-NULL, *ep will point into 942 * the 'value' string at the location where the error exists. 943 * 944 * NOTE: It may be possible to move the non-regex_t version of this into 945 * common code used by library/kernel/boot. 946 */ 947 int 948 nvpair_value_match_regex(nvpair_t *nvp, int ai, 949 char *value, regex_t *value_regex, char **ep) 950 { 951 char *evalue; 952 uint_t a_len; 953 int sr; 954 955 if (ep) 956 *ep = NULL; 957 958 if ((nvp == NULL) || (value == NULL)) 959 return (-1); /* error fail match - invalid args */ 960 961 /* make sure array and index combination make sense */ 962 if ((nvpair_type_is_array(nvp) && (ai < 0)) || 963 (!nvpair_type_is_array(nvp) && (ai >= 0))) 964 return (-1); /* error fail match - bad index */ 965 966 /* non-string values should be single 'chunk' */ 967 if ((nvpair_type(nvp) != DATA_TYPE_STRING) && 968 (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) { 969 value += strspn(value, " \t"); 970 evalue = value + strcspn(value, " \t"); 971 if (*evalue) { 972 if (ep) 973 *ep = evalue; 974 return (-1); /* error fail match - syntax */ 975 } 976 } 977 978 sr = EOF; 979 switch (nvpair_type(nvp)) { 980 case DATA_TYPE_STRING: { 981 char *val; 982 983 /* check string value for match */ 984 if (nvpair_value_string(nvp, &val) == 0) { 985 if (value_regex) { 986 if (regexec(value_regex, val, 987 (size_t)0, NULL, 0) == 0) 988 return (1); /* match */ 989 } else { 990 if (strcmp(value, val) == 0) 991 return (1); /* match */ 992 } 993 } 994 break; 995 } 996 case DATA_TYPE_STRING_ARRAY: { 997 char **val_array; 998 999 /* check indexed string value of array for match */ 1000 if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) && 1001 (ai < a_len)) { 1002 if (value_regex) { 1003 if (regexec(value_regex, val_array[ai], 1004 (size_t)0, NULL, 0) == 0) 1005 return (1); 1006 } else { 1007 if (strcmp(value, val_array[ai]) == 0) 1008 return (1); 1009 } 1010 } 1011 break; 1012 } 1013 case DATA_TYPE_BYTE: { 1014 uchar_t val, val_arg; 1015 1016 /* scanf uchar_t from value and check for match */ 1017 sr = sscanf(value, "%c", &val_arg); 1018 if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) && 1019 (val == val_arg)) 1020 return (1); 1021 break; 1022 } 1023 case DATA_TYPE_BYTE_ARRAY: { 1024 uchar_t *val_array, val_arg; 1025 1026 1027 /* check indexed value of array for match */ 1028 sr = sscanf(value, "%c", &val_arg); 1029 if ((sr == 1) && 1030 (nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) && 1031 (ai < a_len) && 1032 (val_array[ai] == val_arg)) 1033 return (1); 1034 break; 1035 } 1036 case DATA_TYPE_INT8: { 1037 int8_t val, val_arg; 1038 1039 /* scanf int8_t from value and check for match */ 1040 sr = sscanf(value, "%"SCNi8, &val_arg); 1041 if ((sr == 1) && 1042 (nvpair_value_int8(nvp, &val) == 0) && 1043 (val == val_arg)) 1044 return (1); 1045 break; 1046 } 1047 case DATA_TYPE_INT8_ARRAY: { 1048 int8_t *val_array, val_arg; 1049 1050 /* check indexed value of array for match */ 1051 sr = sscanf(value, "%"SCNi8, &val_arg); 1052 if ((sr == 1) && 1053 (nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) && 1054 (ai < a_len) && 1055 (val_array[ai] == val_arg)) 1056 return (1); 1057 break; 1058 } 1059 case DATA_TYPE_UINT8: { 1060 uint8_t val, val_arg; 1061 1062 /* scanf uint8_t from value and check for match */ 1063 sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg); 1064 if ((sr == 1) && 1065 (nvpair_value_uint8(nvp, &val) == 0) && 1066 (val == val_arg)) 1067 return (1); 1068 break; 1069 } 1070 case DATA_TYPE_UINT8_ARRAY: { 1071 uint8_t *val_array, val_arg; 1072 1073 /* check indexed value of array for match */ 1074 sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg); 1075 if ((sr == 1) && 1076 (nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) && 1077 (ai < a_len) && 1078 (val_array[ai] == val_arg)) 1079 return (1); 1080 break; 1081 } 1082 case DATA_TYPE_INT16: { 1083 int16_t val, val_arg; 1084 1085 /* scanf int16_t from value and check for match */ 1086 sr = sscanf(value, "%"SCNi16, &val_arg); 1087 if ((sr == 1) && 1088 (nvpair_value_int16(nvp, &val) == 0) && 1089 (val == val_arg)) 1090 return (1); 1091 break; 1092 } 1093 case DATA_TYPE_INT16_ARRAY: { 1094 int16_t *val_array, val_arg; 1095 1096 /* check indexed value of array for match */ 1097 sr = sscanf(value, "%"SCNi16, &val_arg); 1098 if ((sr == 1) && 1099 (nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) && 1100 (ai < a_len) && 1101 (val_array[ai] == val_arg)) 1102 return (1); 1103 break; 1104 } 1105 case DATA_TYPE_UINT16: { 1106 uint16_t val, val_arg; 1107 1108 /* scanf uint16_t from value and check for match */ 1109 sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg); 1110 if ((sr == 1) && 1111 (nvpair_value_uint16(nvp, &val) == 0) && 1112 (val == val_arg)) 1113 return (1); 1114 break; 1115 } 1116 case DATA_TYPE_UINT16_ARRAY: { 1117 uint16_t *val_array, val_arg; 1118 1119 /* check indexed value of array for match */ 1120 sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg); 1121 if ((sr == 1) && 1122 (nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) && 1123 (ai < a_len) && 1124 (val_array[ai] == val_arg)) 1125 return (1); 1126 break; 1127 } 1128 case DATA_TYPE_INT32: { 1129 int32_t val, val_arg; 1130 1131 /* scanf int32_t from value and check for match */ 1132 sr = sscanf(value, "%"SCNi32, &val_arg); 1133 if ((sr == 1) && 1134 (nvpair_value_int32(nvp, &val) == 0) && 1135 (val == val_arg)) 1136 return (1); 1137 break; 1138 } 1139 case DATA_TYPE_INT32_ARRAY: { 1140 int32_t *val_array, val_arg; 1141 1142 /* check indexed value of array for match */ 1143 sr = sscanf(value, "%"SCNi32, &val_arg); 1144 if ((sr == 1) && 1145 (nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) && 1146 (ai < a_len) && 1147 (val_array[ai] == val_arg)) 1148 return (1); 1149 break; 1150 } 1151 case DATA_TYPE_UINT32: { 1152 uint32_t val, val_arg; 1153 1154 /* scanf uint32_t from value and check for match */ 1155 sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg); 1156 if ((sr == 1) && 1157 (nvpair_value_uint32(nvp, &val) == 0) && 1158 (val == val_arg)) 1159 return (1); 1160 break; 1161 } 1162 case DATA_TYPE_UINT32_ARRAY: { 1163 uint32_t *val_array, val_arg; 1164 1165 /* check indexed value of array for match */ 1166 sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg); 1167 if ((sr == 1) && 1168 (nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) && 1169 (ai < a_len) && 1170 (val_array[ai] == val_arg)) 1171 return (1); 1172 break; 1173 } 1174 case DATA_TYPE_INT64: { 1175 int64_t val, val_arg; 1176 1177 /* scanf int64_t from value and check for match */ 1178 sr = sscanf(value, "%"SCNi64, &val_arg); 1179 if ((sr == 1) && 1180 (nvpair_value_int64(nvp, &val) == 0) && 1181 (val == val_arg)) 1182 return (1); 1183 break; 1184 } 1185 case DATA_TYPE_INT64_ARRAY: { 1186 int64_t *val_array, val_arg; 1187 1188 /* check indexed value of array for match */ 1189 sr = sscanf(value, "%"SCNi64, &val_arg); 1190 if ((sr == 1) && 1191 (nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) && 1192 (ai < a_len) && 1193 (val_array[ai] == val_arg)) 1194 return (1); 1195 break; 1196 } 1197 case DATA_TYPE_UINT64: { 1198 uint64_t val_arg, val; 1199 1200 /* scanf uint64_t from value and check for match */ 1201 sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg); 1202 if ((sr == 1) && 1203 (nvpair_value_uint64(nvp, &val) == 0) && 1204 (val == val_arg)) 1205 return (1); 1206 break; 1207 } 1208 case DATA_TYPE_UINT64_ARRAY: { 1209 uint64_t *val_array, val_arg; 1210 1211 /* check indexed value of array for match */ 1212 sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg); 1213 if ((sr == 1) && 1214 (nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) && 1215 (ai < a_len) && 1216 (val_array[ai] == val_arg)) 1217 return (1); 1218 break; 1219 } 1220 case DATA_TYPE_BOOLEAN_VALUE: { 1221 int32_t val_arg; 1222 boolean_t val; 1223 1224 /* scanf boolean_t from value and check for match */ 1225 sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg); 1226 if ((sr == 1) && 1227 (nvpair_value_boolean_value(nvp, &val) == 0) && 1228 (val == val_arg)) 1229 return (1); 1230 break; 1231 } 1232 case DATA_TYPE_BOOLEAN_ARRAY: { 1233 boolean_t *val_array; 1234 int32_t val_arg; 1235 1236 /* check indexed value of array for match */ 1237 sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg); 1238 if ((sr == 1) && 1239 (nvpair_value_boolean_array(nvp, 1240 &val_array, &a_len) == 0) && 1241 (ai < a_len) && 1242 (val_array[ai] == val_arg)) 1243 return (1); 1244 break; 1245 } 1246 case DATA_TYPE_HRTIME: 1247 case DATA_TYPE_NVLIST: 1248 case DATA_TYPE_NVLIST_ARRAY: 1249 case DATA_TYPE_BOOLEAN: 1250 case DATA_TYPE_DOUBLE: 1251 case DATA_TYPE_UNKNOWN: 1252 default: 1253 /* 1254 * unknown/unsupported data type 1255 */ 1256 return (-1); /* error fail match */ 1257 } 1258 1259 /* 1260 * check to see if sscanf failed conversion, return approximate 1261 * pointer to problem 1262 */ 1263 if (sr != 1) { 1264 if (ep) 1265 *ep = value; 1266 return (-1); /* error fail match - syntax */ 1267 } 1268 1269 return (0); /* fail match */ 1270 } 1271 1272 int 1273 nvpair_value_match(nvpair_t *nvp, int ai, char *value, char **ep) 1274 { 1275 return (nvpair_value_match_regex(nvp, ai, value, NULL, ep)); 1276 } 1277