1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * After having been declared, events, FMRIs and authorities must be defined
  29  * (instantiated) before they can be used as the subjects of commands.
  30  */
  31 
  32 #include <sys/sysmacros.h>
  33 #include <libnvpair.h>
  34 #include <string.h>
  35 #include <assert.h>
  36 
  37 #include <inj_event.h>
  38 #include <inj_err.h>
  39 #include <inj_lex.h>
  40 #include <inj_string.h>
  41 #include <inj.h>
  42 
  43 static inj_hash_t inj_defns[3];
  44 static int inj_defns_initialized;
  45 
  46 /* Intrinsics (signed and unsigned integer integer constants) */
  47 typedef struct intr {
  48         uchar_t ei_signed;
  49         uchar_t ei_width;
  50 } intr_t;
  51 
  52 static inj_hash_t *
  53 item2hash(inj_itemtype_t item)
  54 {
  55         int i;
  56 
  57         assert(item >= 0 && item < sizeof (inj_defns) / sizeof (inj_hash_t));
  58 
  59         if (!inj_defns_initialized) {
  60                 for (i = 0; i < sizeof (inj_defns) / sizeof (inj_hash_t); i++)
  61                         inj_strhash_create(&inj_defns[i]);
  62                 inj_defns_initialized = 1;
  63         }
  64 
  65         return (&inj_defns[item]);
  66 }
  67 
  68 inj_defn_t *
  69 inj_defn_lookup(const char *name, inj_memtype_t type)
  70 {
  71         inj_hash_t *hash = item2hash(inj_mem2item(type));
  72         inj_var_t *v;
  73 
  74         if ((v = inj_strhash_lookup(hash, name)) == NULL)
  75                 return (NULL);
  76 
  77         return (inj_hash_get_cookie(v));
  78 }
  79 
  80 static void
  81 inj_defn_destroy_memlist(inj_defnmem_t *m)
  82 {
  83         inj_defnmem_t *n;
  84 
  85         for (/* */; m != NULL; m = n) {
  86                 n = inj_list_next(m);
  87 
  88                 switch (m->dfm_type) {
  89                 case DEFNMEM_ARRAY:
  90                 case DEFNMEM_LIST:
  91                         inj_defn_destroy_memlist(inj_list_next(&m->dfm_list));
  92                         break;
  93                 default:
  94                         inj_strfree(m->dfm_str);
  95                 }
  96         }
  97 }
  98 
  99 void
 100 inj_defn_destroy(inj_defn_t *defn)
 101 {
 102         if (defn->defn_name != NULL)
 103                 inj_strfree(defn->defn_name);
 104 
 105         nvlist_free(defn->defn_nvl);
 106 
 107         inj_defn_destroy_memlist(inj_list_next(&defn->defn_members));
 108 }
 109 
 110 static inj_defnmem_t *
 111 inj_defn_mem_create_common(inj_defnmemtype_t type)
 112 {
 113         inj_defnmem_t *dfm = inj_zalloc(sizeof (inj_defnmem_t));
 114 
 115         dfm->dfm_type = type;
 116         dfm->dfm_lineno = yylineno;
 117 
 118         return (dfm);
 119 }
 120 
 121 inj_defnmem_t *
 122 inj_defn_mem_create(const char *str, inj_defnmemtype_t type)
 123 {
 124         inj_defnmem_t *dfm = inj_defn_mem_create_common(type);
 125 
 126         dfm->dfm_str = str;
 127 
 128         return (dfm);
 129 }
 130 
 131 inj_defnmem_t *
 132 inj_defn_mem_create_list(inj_defn_t *list, inj_defnmemtype_t type)
 133 {
 134         inj_defnmem_t *dfm = inj_defn_mem_create_common(type);
 135 
 136         dfm->dfm_list = list->defn_members;
 137 
 138         inj_free(list, sizeof (inj_defn_t));
 139 
 140         return (dfm);
 141 }
 142 
 143 inj_defn_t *
 144 inj_defn_create(inj_defnmem_t *dfm)
 145 {
 146         inj_defn_t *defn = inj_zalloc(sizeof (inj_defn_t));
 147 
 148         defn->defn_lineno = yylineno;
 149 
 150         inj_list_append(&defn->defn_members, dfm);
 151 
 152         return (defn);
 153 }
 154 
 155 void
 156 inj_defn_addmem(inj_defn_t *defn, inj_defnmem_t *dfm)
 157 {
 158         inj_list_append(&defn->defn_members, dfm);
 159 }
 160 
 161 /*
 162  * Validate the dimensions of an array.  If the declared array size was zero,
 163  * accept (and return) whatever the definition used.  If fewer cells were
 164  * defined than were declared, return the declared size - the calling code will
 165  * fill the remaining cells with zeros.  The definition of more than the
 166  * declared number of cells triggers an error.  We print and error message in
 167  * this case and return the declared number.  This will allow processing to
 168  * continue.  The act of emitting the error will guarantee that we never
 169  * pass from parsing to program execution.
 170  */
 171 static size_t
 172 array_dim_check(inj_declmem_t *dlm, inj_defnmem_t *dfm)
 173 {
 174         inj_list_t *l;
 175         size_t dfnelems;
 176 
 177         for (dfnelems = 0, l = inj_list_next(&dfm->dfm_list); l != NULL;
 178             l = inj_list_next(l), dfnelems++);
 179 
 180         if (dlm->dlm_arrdim != 0 && dlm->dlm_arrdim != dfnelems) {
 181                 yyerror(" %d: defined array has %d elements, expected %d\n",
 182                     dfm->dfm_lineno, dfnelems, dlm->dlm_arrdim);
 183                 dfnelems = dlm->dlm_arrdim;
 184         }
 185 
 186         return (MAX(dfnelems, dlm->dlm_arrdim));
 187 }
 188 
 189 /*
 190  * The inj_defn_memcmp_* routines serve two purposes.  First, they compare a
 191  * given defined member with the corresponding declared member, signalling an
 192  * error if the two are incompatible.
 193  *
 194  * Assuming that validation succeeds, an entry is added to the passed nvlist
 195  * for the defined member.
 196  */
 197 
 198 /* Used to ease signed and unsigned integer validation */
 199 static const intr_t inj_intrinsics[] = {
 200         { 0, 0 }, /* MEMTYPE_UNKNOWN */
 201         { 1, 8 }, { 1, 16 }, { 1, 32 }, { 1, 64 },
 202         { 0, 8 }, { 0, 16 }, { 0, 32 }, { 0, 64 }
 203 };
 204 
 205 static int
 206 inj_defn_memcmp_signed(const intr_t *intr, inj_declmem_t *dlm,
 207     inj_defnmem_t *dfm, nvlist_t *nvl)
 208 {
 209         longlong_t val;
 210 
 211         if (dfm->dfm_type != DEFNMEM_IMM && dfm->dfm_type != DEFNMEM_IDENT)
 212                 return (inj_set_errno(EINVAL));
 213 
 214         if (inj_strtoll(dfm->dfm_str, intr->ei_width, &val) < 0)
 215                 return (-1); /* errno is set for us */
 216 
 217         switch (dlm->dlm_type) {
 218         case MEMTYPE_INT8:
 219                 errno = nvlist_add_int8(nvl, (char *)dlm->dlm_name,
 220                     (int8_t)val);
 221                 break;
 222         case MEMTYPE_INT16:
 223                 errno = nvlist_add_int16(nvl, (char *)dlm->dlm_name,
 224                     (int16_t)val);
 225                 break;
 226         case MEMTYPE_INT32:
 227                 errno = nvlist_add_int32(nvl, (char *)dlm->dlm_name,
 228                     (int32_t)val);
 229                 break;
 230         case MEMTYPE_INT64:
 231                 errno = nvlist_add_int64(nvl, (char *)dlm->dlm_name,
 232                     (int64_t)val);
 233         }
 234 
 235         if (errno != 0)
 236                 die("failed to add member %s\n", dlm->dlm_name);
 237 
 238         return (0);
 239 }
 240 
 241 static int
 242 inj_defn_memcmp_unsigned(const intr_t *intr, inj_declmem_t *dlm,
 243     inj_defnmem_t *dfm, nvlist_t *nvl)
 244 {
 245         u_longlong_t val;
 246 
 247         if (dfm->dfm_type != DEFNMEM_IMM && dfm->dfm_type != DEFNMEM_IDENT)
 248                 return (inj_set_errno(EINVAL));
 249 
 250         if (inj_strtoull(dfm->dfm_str, intr->ei_width, &val) < 0)
 251                 return (-1); /* errno is set for us */
 252 
 253         switch (dlm->dlm_type) {
 254         case MEMTYPE_UINT8:
 255                 errno = nvlist_add_uint8(nvl, (char *)dlm->dlm_name,
 256                     (uint8_t)val);
 257                 break;
 258         case MEMTYPE_UINT16:
 259                 errno = nvlist_add_uint16(nvl, (char *)dlm->dlm_name,
 260                     (uint16_t)val);
 261                 break;
 262         case MEMTYPE_UINT32:
 263                 errno = nvlist_add_uint32(nvl, (char *)dlm->dlm_name,
 264                     (uint32_t)val);
 265                 break;
 266         case MEMTYPE_UINT64:
 267                 errno = nvlist_add_uint64(nvl, (char *)dlm->dlm_name,
 268                     (uint64_t)val);
 269         }
 270 
 271         if (errno != 0)
 272                 die("failed to add member %s\n", dlm->dlm_name);
 273 
 274         return (0);
 275 }
 276 
 277 /* Validate an array of (un)signed integers. */
 278 static int
 279 inj_defn_memcmp_intr_array(const intr_t *cont, inj_declmem_t *dlm,
 280     inj_defnmem_t *dfm, nvlist_t *nvl)
 281 {
 282         typedef int (*adder_t)();
 283         static const adder_t signed_adders[] = {
 284                 NULL, nvlist_add_int8_array, nvlist_add_int16_array,
 285                 NULL, nvlist_add_int32_array, NULL, NULL, NULL,
 286                 nvlist_add_int64_array
 287         };
 288         static const adder_t unsigned_adders[] = {
 289                 NULL,
 290                 nvlist_add_uint8_array, nvlist_add_uint16_array,
 291                 NULL, nvlist_add_uint32_array, NULL, NULL, NULL,
 292                 nvlist_add_uint64_array
 293         };
 294 
 295         union {
 296                 char *a;
 297                 int8_t *a8; uint8_t *au8;
 298                 int16_t *a16; uint16_t *au16;
 299                 int32_t *a32; uint32_t *au32;
 300                 int64_t *a64; uint64_t *au64;
 301         } a;
 302 
 303         int (*adder)(nvlist_t *, const char *, char *, uint_t);
 304         size_t nelems;
 305         inj_defnmem_t *elem;
 306         char *arrbase, *arr;
 307         size_t arrsz;
 308         int err = 0;
 309         int i;
 310 
 311         if (dfm->dfm_type != DEFNMEM_ARRAY)
 312                 return (inj_set_errno(EINVAL));
 313 
 314         /*
 315          * Each nvlist array adder wants an array of its own type as input,
 316          * which is reasonable, but it complicates our general implementation.
 317          * We fight back with casting magic.
 318          */
 319 
 320         nelems = array_dim_check(dlm, dfm);
 321         arrsz = (nelems + 1) * (cont->ei_width / NBBY);
 322         arrbase = inj_zalloc(arrsz);
 323         a.a = arr = (char *)P2ROUNDUP((uintptr_t)arrbase,
 324             cont->ei_width / NBBY);
 325 
 326         adder = (cont->ei_signed ? signed_adders :
 327             unsigned_adders)[cont->ei_width / NBBY];
 328         assert(adder != NULL);
 329 
 330         for (i = 1, elem = inj_list_next(&dfm->dfm_list); elem != NULL;
 331             elem = inj_list_next(elem), i++) {
 332                 if (elem->dfm_type != DEFNMEM_IMM &&
 333                     elem->dfm_type != DEFNMEM_IDENT) {
 334                         yyerror(" %d: array cell %d is invalid\n",
 335                             dfm->dfm_lineno, i);
 336                         err++;
 337                         continue;
 338                 }
 339 
 340                 if (cont->ei_signed) {
 341                         longlong_t val;
 342 
 343                         if (inj_strtoll(elem->dfm_str, cont->ei_width,
 344                             &val) < 0) {
 345                                 yyerror(" %d: array cell %d %s\n",
 346                                     dfm->dfm_lineno, i, (errno == ERANGE ?
 347                                     "out of range for type" : "invalid"));
 348                                 err++;
 349                                 continue;
 350                         }
 351 
 352                         switch (cont->ei_width) {
 353                         case 8:
 354                                 *a.a8++ = (int8_t)val;
 355                                 break;
 356                         case 16:
 357                                 *a.a16++ = (int16_t)val;
 358                                 break;
 359                         case 32:
 360                                 *a.a32++ = (int32_t)val;
 361                                 break;
 362                         default:
 363                                 *a.a64++ = (int64_t)val;
 364                         }
 365 
 366                 } else {
 367                         u_longlong_t val;
 368 
 369                         if (inj_strtoull(elem->dfm_str, cont->ei_width,
 370                             &val) < 0) {
 371                                 yyerror(" %d: array cell %d %s\n",
 372                                     dfm->dfm_lineno, i, (errno == ERANGE ?
 373                                     "out of range for type" : "invalid"));
 374                                 err++;
 375                                 continue;
 376                         }
 377 
 378                         switch (cont->ei_width) {
 379                         case 8:
 380                                 *a.au8++ = (uint8_t)val;
 381                                 break;
 382                         case 16:
 383                                 *a.au16++ = (uint16_t)val;
 384                                 break;
 385                         case 32:
 386                                 *a.au32++ = (uint32_t)val;
 387                                 break;
 388                         default:
 389                                 *a.au64++ = (uint64_t)val;
 390                         }
 391                 }
 392         }
 393 
 394         if (err == 0 && (errno = adder(nvl, dlm->dlm_name, arr, nelems)) != 0)
 395                 die("failed to add array member %s", dlm->dlm_name);
 396 
 397         inj_free(arrbase, arrsz);
 398 
 399         if (err != 0)
 400                 return (inj_set_errno(EINVAL));
 401 
 402         return (0);
 403 }
 404 
 405 static int
 406 bool2val(const char *str, boolean_t *valp)
 407 {
 408         if (strcasecmp(str, "true") == 0)
 409                 *valp = 1;
 410         else if (strcasecmp(str, "false") == 0)
 411                 *valp = 0;
 412         else
 413                 return (-1);
 414 
 415         return (0);
 416 }
 417 
 418 static int
 419 inj_defn_memcmp_bool(inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl)
 420 {
 421         boolean_t val;
 422 
 423         if (dfm->dfm_type != DEFNMEM_IDENT)
 424                 return (inj_set_errno(EINVAL));
 425 
 426         if (bool2val(dfm->dfm_str, &val) < 0)
 427                 return (inj_set_errno(EINVAL));
 428 
 429         if ((errno = nvlist_add_boolean_value(nvl, (char *)dlm->dlm_name,
 430             val)) != 0)
 431                 die("failed to add boolean member %s", dlm->dlm_name);
 432 
 433         return (0);
 434 }
 435 
 436 static int
 437 inj_defn_memcmp_bool_array(inj_declmem_t *dlm, inj_defnmem_t *dfm,
 438     nvlist_t *nvl)
 439 {
 440         inj_defnmem_t *elem;
 441         boolean_t *arr;
 442         size_t nelems, arrsz;
 443         int err = 0;
 444         int i;
 445 
 446         if (dfm->dfm_type != DEFNMEM_ARRAY)
 447                 return (inj_set_errno(EINVAL));
 448 
 449         nelems = array_dim_check(dlm, dfm);
 450         arrsz = nelems * sizeof (boolean_t);
 451         arr = inj_zalloc(arrsz);
 452 
 453         for (i = 0, elem = inj_list_next(&dfm->dfm_list); elem != NULL;
 454             elem = inj_list_next(elem), i++) {
 455                 if (elem->dfm_type != DEFNMEM_IDENT) {
 456                         yyerror(" %d: array cell %d is invalid\n",
 457                             dfm->dfm_lineno, i + 1);
 458                         err++;
 459                         continue;
 460                 }
 461 
 462                 if (bool2val(elem->dfm_str, &arr[i]) < 0)
 463                         return (inj_set_errno(EINVAL));
 464         }
 465 
 466         if (err == 0 && (errno = nvlist_add_boolean_array(nvl,
 467             (char *)dlm->dlm_name, arr, nelems)) != 0)
 468                 die("failed to add boolean array member %s", dlm->dlm_name);
 469 
 470         inj_free(arr, arrsz);
 471 
 472         return (0);
 473 }
 474 
 475 /* Used for both strings and enums */
 476 static int
 477 inj_defn_memcmp_strenum(inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl)
 478 {
 479         inj_defnmemtype_t defnmemtype = (dlm->dlm_type == MEMTYPE_ENUM ?
 480             DEFNMEM_IDENT : DEFNMEM_QSTRING);
 481         const char *strenum = (dlm->dlm_type == MEMTYPE_ENUM ? "enum" :
 482             "string");
 483 
 484         if (dfm->dfm_type != defnmemtype)
 485                 return (inj_set_errno(EINVAL));
 486 
 487         if ((errno = nvlist_add_string(nvl, (char *)dlm->dlm_name,
 488             (char *)dfm->dfm_str)) != 0)
 489                 die("failed to add %s member %s", strenum, dlm->dlm_name);
 490 
 491         return (0);
 492 }
 493 
 494 static int
 495 inj_defn_memcmp_strenum_array(inj_declmem_t *dlm, inj_defnmem_t *dfm,
 496     nvlist_t *nvl)
 497 {
 498         inj_defnmemtype_t defnmemtype = (dlm->dlm_type == MEMTYPE_ENUM ?
 499             DEFNMEM_IDENT : DEFNMEM_QSTRING);
 500         const char *strenum = (dlm->dlm_type == MEMTYPE_ENUM ? "enum" :
 501             "string");
 502 
 503         inj_defnmem_t *elem;
 504         size_t nelems, arrsz;
 505         const char **arr;
 506         int err = 0;
 507         int i;
 508 
 509         if (dfm->dfm_type != DEFNMEM_ARRAY)
 510                 return (inj_set_errno(EINVAL));
 511 
 512         nelems = array_dim_check(dlm, dfm);
 513         arrsz = nelems * sizeof (char *);
 514         arr = inj_zalloc(arrsz);
 515 
 516         for (i = 0, elem = inj_list_next(&dfm->dfm_list); elem != NULL;
 517             elem = inj_list_next(elem), i++) {
 518                 if (elem->dfm_type != defnmemtype) {
 519                         yyerror(" %d: array cell %d is invalid\n",
 520                             dfm->dfm_lineno, i + 1);
 521                         err++;
 522                         continue;
 523                 }
 524 
 525                 if (dlm->dlm_type == MEMTYPE_ENUM &&
 526                     inj_strhash_lookup(dlm->dlm_enumvals, elem->dfm_str) ==
 527                     NULL) {
 528                         yyerror(" %d: invalid enum value %s\n",
 529                             dfm->dfm_lineno, elem->dfm_str);
 530                         err++;
 531                         continue;
 532                 }
 533 
 534                 arr[i] = elem->dfm_str;
 535         }
 536 
 537         if (err == 0 && (errno = nvlist_add_string_array(nvl,
 538             dlm->dlm_name, (char **)arr, nelems)) != 0)
 539                 die("failed to add %s array member %s", strenum, dlm->dlm_name);
 540 
 541         inj_free(arr, arrsz);
 542         return (0);
 543 }
 544 
 545 /*
 546  * Validator for embedded lists (events, fmris, authorities, lists, etc.).
 547  * There are two cases to deal with here.  The user could either have provided
 548  * the name of a previously-defined list, in which case we just make a copy of
 549  * said list for insertion into ours.  Alternatively, the user could simply
 550  * define a new list here.  In that case, we recursively invoke the member
 551  * comparator, but against the list type for the member being defined.
 552  */
 553 static nvlist_t *inj_defn_validate_memlist(inj_declmem_t *, inj_defnmem_t *);
 554 
 555 /* Embedded definition */
 556 static nvlist_t *
 557 inj_defn_memcmp_sub_list(inj_declmem_t *dlm, inj_defnmem_t *dfm)
 558 {
 559         inj_declmem_t *subdlm = inj_list_next(&dlm->dlm_decl->decl_members);
 560         inj_defnmem_t *subdfm = inj_list_next(&dfm->dfm_list);
 561 
 562         return (inj_defn_validate_memlist(subdlm, subdfm));
 563 }
 564 
 565 /* Reference to previously-defined thing */
 566 static nvlist_t *
 567 inj_defn_memcmp_sub_defined(inj_declmem_t *dlm, inj_defnmem_t *dfm)
 568 {
 569         inj_defn_t *subdefn;
 570         nvlist_t *new;
 571 
 572         if ((subdefn = inj_defn_lookup(dfm->dfm_str, dlm->dlm_type)) == NULL) {
 573                 yyerror(" %d: reference to undefined %s %s\n", dfm->dfm_lineno,
 574                     inj_mem2str(dlm->dlm_type), dfm->dfm_str);
 575                 (void) inj_set_errno(EINVAL);
 576                 return (NULL);
 577         }
 578 
 579         if (subdefn->defn_decl != dlm->dlm_decl) {
 580                 yyerror(" %d: %s %s is not a(n) %s\n", dfm->dfm_lineno,
 581                     inj_mem2str(dlm->dlm_type), dfm->dfm_str,
 582                     subdefn->defn_decl->decl_name);
 583                 (void) inj_set_errno(EINVAL);
 584                 return (NULL);
 585         }
 586 
 587         assert(subdefn->defn_nvl != NULL);
 588 
 589         if ((errno = nvlist_dup(subdefn->defn_nvl, &new, 0)) != 0) {
 590                 die("failed to duplicate %s list %s",
 591                     inj_item2str(subdefn->defn_decl->decl_type), dfm->dfm_str);
 592         }
 593 
 594         return (new);
 595 }
 596 
 597 static nvlist_t *
 598 inj_defn_memcmp_sub_makenvl(inj_declmem_t *dlm, inj_defnmem_t *dfm)
 599 {
 600         inj_defnmemtype_t dftype = dfm->dfm_type;
 601         inj_memtype_t dltype = dlm->dlm_type;
 602         nvlist_t *new = NULL;
 603 
 604         if (dftype == DEFNMEM_LIST)
 605                 new = inj_defn_memcmp_sub_list(dlm, dfm);
 606         else if (dftype == DEFNMEM_IDENT && (dltype == MEMTYPE_EVENT ||
 607             dltype == MEMTYPE_FMRI || dltype == MEMTYPE_AUTH))
 608                 new = inj_defn_memcmp_sub_defined(dlm, dfm);
 609         else
 610                 (void) inj_set_errno(EINVAL);
 611 
 612         return (new);
 613 }
 614 
 615 /* A single sub-list */
 616 static int
 617 inj_defn_memcmp_sub(inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl)
 618 {
 619         nvlist_t *new;
 620 
 621         if ((new = inj_defn_memcmp_sub_makenvl(dlm, dfm)) == NULL)
 622                 return (-1); /* errno is set for us */
 623 
 624         if ((errno = nvlist_add_nvlist(nvl, (char *)dlm->dlm_name,
 625             new)) != 0)
 626                 die("failed to add list member %s", dlm->dlm_name);
 627 
 628         return (0);
 629 }
 630 
 631 /* An array of sub-lists (for example, an array of events of a given type) */
 632 static int
 633 inj_defn_memcmp_sub_array(inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl)
 634 {
 635         size_t nelems, arrsz;
 636         inj_defnmem_t *elem;
 637         nvlist_t **arr;
 638         int err = 0;
 639         int i;
 640 
 641         if (dfm->dfm_type != DEFNMEM_ARRAY)
 642                 return (inj_set_errno(EINVAL));
 643 
 644         nelems = array_dim_check(dlm, dfm);
 645         arrsz = nelems * sizeof (char *);
 646         arr = inj_zalloc(arrsz);
 647 
 648         for (i = 0, elem = inj_list_next(&dfm->dfm_list); elem != NULL;
 649             elem = inj_list_next(elem), i++) {
 650                 if ((arr[i] = inj_defn_memcmp_sub_makenvl(dlm, elem)) == NULL) {
 651                         yyerror(" %d: array cell %d is invalid\n",
 652                             elem->dfm_lineno, i + 1);
 653                         err++;
 654                         continue;
 655                 }
 656         }
 657 
 658         if (err == 0 && (errno = nvlist_add_nvlist_array(nvl,
 659             (char *)dlm->dlm_name, arr, nelems)) != 0)
 660                 die("failed to add nvlist list member %s", dlm->dlm_name);
 661 
 662         inj_free(arr, arrsz);
 663 
 664         return (0);
 665 }
 666 
 667 /*
 668  * The declaration-definition member comparator.  Designed to recursive
 669  * invocation to allow for the validation of embedded/referenced lists.
 670  */
 671 nvlist_t *
 672 inj_defn_validate_memlist(inj_declmem_t *dlm, inj_defnmem_t *dfm)
 673 {
 674         const intr_t *intr;
 675         nvlist_t *nvl;
 676         int rc, nmem, dlnmem, dfnmem;
 677         int err = 0;
 678 
 679         if ((errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
 680                 die("failed to allocate nvl for event");
 681 
 682         for (nmem = 1; dlm != NULL && dfm != NULL;
 683             dlm = inj_list_next(dlm), dfm = inj_list_next(dfm), nmem++) {
 684 
 685                 switch (dlm->dlm_type) {
 686                 case MEMTYPE_INT8:
 687                 case MEMTYPE_INT16:
 688                 case MEMTYPE_INT32:
 689                 case MEMTYPE_INT64:
 690                         intr = &inj_intrinsics[dlm->dlm_type];
 691 
 692                         if (dlm->dlm_flags & DECLMEM_F_ARRAY) {
 693                                 rc = inj_defn_memcmp_intr_array(intr, dlm, dfm,
 694                                     nvl);
 695                         } else {
 696                                 rc = inj_defn_memcmp_signed(intr, dlm, dfm,
 697                                     nvl);
 698                         }
 699                         break;
 700 
 701                 case MEMTYPE_UINT8:
 702                 case MEMTYPE_UINT16:
 703                 case MEMTYPE_UINT32:
 704                 case MEMTYPE_UINT64:
 705                         intr = &inj_intrinsics[dlm->dlm_type];
 706 
 707                         if (dlm->dlm_flags & DECLMEM_F_ARRAY) {
 708                                 rc = inj_defn_memcmp_intr_array(intr, dlm, dfm,
 709                                     nvl);
 710                         } else {
 711                                 rc = inj_defn_memcmp_unsigned(intr, dlm, dfm,
 712                                     nvl);
 713                         }
 714                         break;
 715 
 716                 case MEMTYPE_BOOL:
 717                         if (dlm->dlm_flags & DECLMEM_F_ARRAY)
 718                                 rc = inj_defn_memcmp_bool_array(dlm, dfm, nvl);
 719                         else
 720                                 rc = inj_defn_memcmp_bool(dlm, dfm, nvl);
 721                         break;
 722 
 723                 case MEMTYPE_STRING:
 724                         if (dlm->dlm_flags & DECLMEM_F_ARRAY) {
 725                                 rc = inj_defn_memcmp_strenum_array(dlm, dfm,
 726                                     nvl);
 727                         } else
 728                                 rc = inj_defn_memcmp_strenum(dlm, dfm, nvl);
 729                         break;
 730 
 731                 case MEMTYPE_ENUM:
 732                         if (dlm->dlm_flags & DECLMEM_F_ARRAY) {
 733                                 rc = inj_defn_memcmp_strenum_array(dlm, dfm,
 734                                     nvl);
 735                         } else
 736                                 rc = inj_defn_memcmp_strenum(dlm, dfm, nvl);
 737                         break;
 738 
 739                 case MEMTYPE_EVENT:
 740                 case MEMTYPE_FMRI:
 741                 case MEMTYPE_AUTH:
 742                 case MEMTYPE_LIST:
 743                         if (dlm->dlm_flags & DECLMEM_F_ARRAY)
 744                                 rc = inj_defn_memcmp_sub_array(dlm, dfm, nvl);
 745                         else
 746                                 rc = inj_defn_memcmp_sub(dlm, dfm, nvl);
 747                         break;
 748 
 749                 default:
 750                         die("unknown decl member type %d on member %s\n",
 751                             dlm->dlm_type, dlm->dlm_name);
 752                 }
 753 
 754                 if (rc < 0) {
 755                         yyerror(" %d: %s for member %s\n", dfm->dfm_lineno,
 756                             (errno == ERANGE ? "value out of range" :
 757                             "invalid value"), dlm->dlm_name);
 758                         err++;
 759                 }
 760         }
 761 
 762         dlnmem = dfnmem = nmem;
 763 
 764         while (dlm != NULL) {
 765                 dlm = inj_list_next(dlm);
 766                 dlnmem++;
 767         }
 768 
 769         while (dfm != NULL) {
 770                 dfm = inj_list_next(dfm);
 771                 dfnmem++;
 772         }
 773 
 774         if (dlnmem != dfnmem) {
 775                 yyerror("%d members found, expected %d", dfnmem, dlnmem);
 776                 err++;
 777         }
 778 
 779         if (err > 0) {
 780                 nvlist_free(nvl);
 781                 return (NULL);
 782         }
 783 
 784         return (nvl);
 785 }
 786 
 787 /*
 788  * The members have all been defined.  Validate the members against the
 789  * declaration, and add it to the appropriate "defined" list.
 790  */
 791 void
 792 inj_defn_finish(inj_defn_t *defn, const char *declnm, const char *name,
 793     inj_itemtype_t type)
 794 {
 795         inj_decl_t *decl = inj_decl_lookup(declnm, type);
 796         inj_hash_t *hash = item2hash(type);
 797         inj_declmem_t *dlm;
 798         inj_defnmem_t *dfm;
 799         inj_var_t *v;
 800 
 801         defn->defn_name = name;
 802         defn->defn_decl = decl;
 803 
 804         if (decl == NULL) {
 805                 yyerror("unknown %s type %s\n", inj_item2str(type), declnm);
 806                 inj_defn_destroy(defn);
 807                 return;
 808         }
 809 
 810         dlm = inj_list_next(&decl->decl_members);
 811         dfm = inj_list_next(&defn->defn_members);
 812 
 813         if ((defn->defn_nvl = inj_defn_validate_memlist(dlm, dfm)) == NULL) {
 814                 inj_defn_destroy(defn);
 815                 return;
 816         }
 817 
 818         if (type == ITEMTYPE_EVENT) {
 819                 if ((errno = nvlist_add_string(defn->defn_nvl, "class",
 820                     (char *)defn->defn_decl->decl_name)) != 0)
 821                         die("failed to add class to %s", name);
 822         }
 823 
 824         if ((v = inj_strhash_lookup(hash, name)) != NULL) {
 825                 inj_defn_t *other = inj_hash_get_cookie(v);
 826 
 827                 yyerror("duplicate %s name %s (other on line %d)\n",
 828                     inj_item2str(type), name, other->defn_lineno);
 829                 inj_defn_destroy(defn);
 830                 return;
 831         }
 832 
 833         (void) inj_strhash_insert(hash, name, (uintptr_t)defn);
 834 }