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