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 *
item2hash(inj_itemtype_t item)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 *
inj_defn_lookup(const char * name,inj_memtype_t type)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
inj_defn_destroy_memlist(inj_defnmem_t * m)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
inj_defn_destroy(inj_defn_t * defn)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 *
inj_defn_mem_create_common(inj_defnmemtype_t type)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 *
inj_defn_mem_create(const char * str,inj_defnmemtype_t type)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 *
inj_defn_mem_create_list(inj_defn_t * list,inj_defnmemtype_t type)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 *
inj_defn_create(inj_defnmem_t * dfm)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
inj_defn_addmem(inj_defn_t * defn,inj_defnmem_t * dfm)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
array_dim_check(inj_declmem_t * dlm,inj_defnmem_t * dfm)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
inj_defn_memcmp_signed(const intr_t * intr,inj_declmem_t * dlm,inj_defnmem_t * dfm,nvlist_t * nvl)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
inj_defn_memcmp_unsigned(const intr_t * intr,inj_declmem_t * dlm,inj_defnmem_t * dfm,nvlist_t * nvl)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
inj_defn_memcmp_intr_array(const intr_t * cont,inj_declmem_t * dlm,inj_defnmem_t * dfm,nvlist_t * nvl)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
bool2val(const char * str,boolean_t * valp)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
inj_defn_memcmp_bool(inj_declmem_t * dlm,inj_defnmem_t * dfm,nvlist_t * nvl)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
inj_defn_memcmp_bool_array(inj_declmem_t * dlm,inj_defnmem_t * dfm,nvlist_t * nvl)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
inj_defn_memcmp_strenum(inj_declmem_t * dlm,inj_defnmem_t * dfm,nvlist_t * nvl)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
inj_defn_memcmp_strenum_array(inj_declmem_t * dlm,inj_defnmem_t * dfm,nvlist_t * nvl)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 *
inj_defn_memcmp_sub_list(inj_declmem_t * dlm,inj_defnmem_t * dfm)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 *
inj_defn_memcmp_sub_defined(inj_declmem_t * dlm,inj_defnmem_t * dfm)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 *
inj_defn_memcmp_sub_makenvl(inj_declmem_t * dlm,inj_defnmem_t * dfm)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
inj_defn_memcmp_sub(inj_declmem_t * dlm,inj_defnmem_t * dfm,nvlist_t * nvl)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
inj_defn_memcmp_sub_array(inj_declmem_t * dlm,inj_defnmem_t * dfm,nvlist_t * nvl)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 *
inj_defn_validate_memlist(inj_declmem_t * dlm,inj_defnmem_t * dfm)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
inj_defn_finish(inj_defn_t * defn,const char * declnm,const char * name,inj_itemtype_t type)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 }
835