Home | History | Annotate | Download | only in common
      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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  *
     25  * tree.c -- routines for manipulating the prop tree
     26  *
     27  * the actions in escparse.y call these routines to construct
     28  * the parse tree.  these routines, in turn, call the check_X()
     29  * routines for semantic checking.
     30  */
     31 
     32 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     33 
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <ctype.h>
     37 #include <strings.h>
     38 #include <alloca.h>
     39 #include "alloc.h"
     40 #include "out.h"
     41 #include "stats.h"
     42 #include "stable.h"
     43 #include "literals.h"
     44 #include "lut.h"
     45 #include "esclex.h"
     46 #include "tree.h"
     47 #include "check.h"
     48 #include "ptree.h"
     49 
     50 static struct node *Root;
     51 
     52 static char *Newname;
     53 
     54 static struct stats *Faultcount;
     55 static struct stats *Upsetcount;
     56 static struct stats *Defectcount;
     57 static struct stats *Errorcount;
     58 static struct stats *Ereportcount;
     59 static struct stats *SERDcount;
     60 static struct stats *STATcount;
     61 static struct stats *ASRUcount;
     62 static struct stats *FRUcount;
     63 static struct stats *Configcount;
     64 static struct stats *Propcount;
     65 static struct stats *Maskcount;
     66 static struct stats *Nodecount;
     67 static struct stats *Namecount;
     68 static struct stats *Nodesize;
     69 
     70 struct lut *Usedprops;
     71 
     72 void
     73 tree_init(void)
     74 {
     75 	Faultcount = stats_new_counter("parser.fault", "fault decls", 1);
     76 	Upsetcount = stats_new_counter("parser.upset", "upset decls", 1);
     77 	Defectcount = stats_new_counter("parser.defect", "defect decls", 1);
     78 	Errorcount = stats_new_counter("parser.error", "error decls", 1);
     79 	Ereportcount = stats_new_counter("parser.ereport", "ereport decls", 1);
     80 	SERDcount = stats_new_counter("parser.SERD", "SERD engine decls", 1);
     81 	STATcount = stats_new_counter("parser.STAT", "STAT engine decls", 1);
     82 	ASRUcount = stats_new_counter("parser.ASRU", "ASRU decls", 1);
     83 	FRUcount = stats_new_counter("parser.FRU", "FRU decls", 1);
     84 	Configcount = stats_new_counter("parser.config", "config stmts", 1);
     85 	Propcount = stats_new_counter("parser.prop", "prop stmts", 1);
     86 	Maskcount = stats_new_counter("parser.mask", "mask stmts", 1);
     87 	Nodecount = stats_new_counter("parser.node", "nodes created", 1);
     88 	Namecount = stats_new_counter("parser.name", "names created", 1);
     89 	Nodesize =
     90 	    stats_new_counter("parser.nodesize", "sizeof(struct node)", 1);
     91 	stats_counter_add(Nodesize, sizeof (struct node));
     92 }
     93 
     94 void
     95 tree_fini(void)
     96 {
     97 	stats_delete(Faultcount);
     98 	stats_delete(Upsetcount);
     99 	stats_delete(Defectcount);
    100 	stats_delete(Errorcount);
    101 	stats_delete(Ereportcount);
    102 	stats_delete(SERDcount);
    103 	stats_delete(STATcount);
    104 	stats_delete(ASRUcount);
    105 	stats_delete(FRUcount);
    106 	stats_delete(Configcount);
    107 	stats_delete(Propcount);
    108 	stats_delete(Maskcount);
    109 	stats_delete(Nodecount);
    110 	stats_delete(Namecount);
    111 	stats_delete(Nodesize);
    112 
    113 	/* free entire parse tree */
    114 	tree_free(Root);
    115 
    116 	/* free up the luts we keep for decls */
    117 	lut_free(Faults, NULL, NULL);
    118 	Faults = NULL;
    119 	lut_free(Upsets, NULL, NULL);
    120 	Upsets = NULL;
    121 	lut_free(Defects, NULL, NULL);
    122 	Defects = NULL;
    123 	lut_free(Errors, NULL, NULL);
    124 	Errors = NULL;
    125 	lut_free(Ereports, NULL, NULL);
    126 	Ereports = NULL;
    127 	lut_free(Ereportenames, NULL, NULL);
    128 	Ereportenames = NULL;
    129 	lut_free(Ereportenames_discard, NULL, NULL);
    130 	Ereportenames_discard = NULL;
    131 	lut_free(SERDs, NULL, NULL);
    132 	SERDs = NULL;
    133 	lut_free(STATs, NULL, NULL);
    134 	STATs = NULL;
    135 	lut_free(ASRUs, NULL, NULL);
    136 	ASRUs = NULL;
    137 	lut_free(FRUs, NULL, NULL);
    138 	FRUs = NULL;
    139 	lut_free(Configs, NULL, NULL);
    140 	Configs = NULL;
    141 	lut_free(Usedprops, NULL, NULL);
    142 	Usedprops = NULL;
    143 
    144 	Props = Lastprops = NULL;
    145 	Masks = Lastmasks = NULL;
    146 	Problems = Lastproblems = NULL;
    147 
    148 	if (Newname != NULL) {
    149 		FREE(Newname);
    150 		Newname = NULL;
    151 	}
    152 }
    153 
    154 /*ARGSUSED*/
    155 static int
    156 nodesize(enum nodetype t, struct node *ret)
    157 {
    158 	int size = sizeof (struct node);
    159 
    160 	switch (t) {
    161 	case T_NAME:
    162 		size += sizeof (ret->u.name) - sizeof (ret->u);
    163 		break;
    164 
    165 	case T_GLOBID:
    166 		size += sizeof (ret->u.globid) - sizeof (ret->u);
    167 		break;
    168 
    169 	case T_TIMEVAL:
    170 	case T_NUM:
    171 		size += sizeof (ret->u.ull) - sizeof (ret->u);
    172 		break;
    173 
    174 	case T_QUOTE:
    175 		size += sizeof (ret->u.quote) - sizeof (ret->u);
    176 		break;
    177 
    178 	case T_FUNC:
    179 		size += sizeof (ret->u.func) - sizeof (ret->u);
    180 		break;
    181 
    182 	case T_FAULT:
    183 	case T_UPSET:
    184 	case T_DEFECT:
    185 	case T_ERROR:
    186 	case T_EREPORT:
    187 	case T_ASRU:
    188 	case T_FRU:
    189 	case T_SERD:
    190 	case T_STAT:
    191 	case T_CONFIG:
    192 	case T_PROP:
    193 	case T_MASK:
    194 		size += sizeof (ret->u.stmt) - sizeof (ret->u);
    195 		break;
    196 
    197 	case T_EVENT:
    198 		size += sizeof (ret->u.event) - sizeof (ret->u);
    199 		break;
    200 
    201 	case T_ARROW:
    202 		size += sizeof (ret->u.arrow) - sizeof (ret->u);
    203 		break;
    204 
    205 	default:
    206 		size += sizeof (ret->u.expr) - sizeof (ret->u);
    207 		break;
    208 	}
    209 	return (size);
    210 }
    211 
    212 struct node *
    213 newnode(enum nodetype t, const char *file, int line)
    214 {
    215 	struct node *ret = NULL;
    216 	int size = nodesize(t, ret);
    217 
    218 	ret = alloc_xmalloc(size);
    219 	stats_counter_bump(Nodecount);
    220 	bzero(ret, size);
    221 	ret->t = t;
    222 	ret->file = (file == NULL) ? "<nofile>" : file;
    223 	ret->line = line;
    224 
    225 	return (ret);
    226 }
    227 
    228 /*ARGSUSED*/
    229 void
    230 tree_free(struct node *root)
    231 {
    232 	if (root == NULL)
    233 		return;
    234 
    235 	switch (root->t) {
    236 	case T_NAME:
    237 		tree_free(root->u.name.child);
    238 		tree_free(root->u.name.next);
    239 		break;
    240 	case T_FUNC:
    241 		tree_free(root->u.func.arglist);
    242 		break;
    243 	case T_AND:
    244 	case T_OR:
    245 	case T_EQ:
    246 	case T_NE:
    247 	case T_ADD:
    248 	case T_DIV:
    249 	case T_MOD:
    250 	case T_MUL:
    251 	case T_SUB:
    252 	case T_LT:
    253 	case T_LE:
    254 	case T_GT:
    255 	case T_GE:
    256 	case T_BITAND:
    257 	case T_BITOR:
    258 	case T_BITXOR:
    259 	case T_BITNOT:
    260 	case T_LSHIFT:
    261 	case T_RSHIFT:
    262 	case T_NVPAIR:
    263 	case T_ASSIGN:
    264 	case T_CONDIF:
    265 	case T_CONDELSE:
    266 	case T_LIST:
    267 		tree_free(root->u.expr.left);
    268 		tree_free(root->u.expr.right);
    269 		break;
    270 	case T_EVENT:
    271 		tree_free(root->u.event.ename);
    272 		tree_free(root->u.event.epname);
    273 		tree_free(root->u.event.eexprlist);
    274 		break;
    275 	case T_NOT:
    276 		tree_free(root->u.expr.left);
    277 		break;
    278 	case T_ARROW:
    279 		tree_free(root->u.arrow.lhs);
    280 		tree_free(root->u.arrow.nnp);
    281 		tree_free(root->u.arrow.knp);
    282 		tree_free(root->u.arrow.rhs);
    283 		break;
    284 	case T_PROP:
    285 	case T_MASK:
    286 		tree_free(root->u.stmt.np);
    287 		break;
    288 	case T_FAULT:
    289 	case T_UPSET:
    290 	case T_DEFECT:
    291 	case T_ERROR:
    292 	case T_EREPORT:
    293 	case T_ASRU:
    294 	case T_FRU:
    295 	case T_SERD:
    296 	case T_STAT:
    297 	case T_CONFIG:
    298 		tree_free(root->u.stmt.np);
    299 		if (root->u.stmt.nvpairs)
    300 			tree_free(root->u.stmt.nvpairs);
    301 		if (root->u.stmt.lutp)
    302 			lut_free(root->u.stmt.lutp, NULL, NULL);
    303 		break;
    304 	case T_TIMEVAL:
    305 	case T_NUM:
    306 	case T_QUOTE:
    307 	case T_GLOBID:
    308 	case T_NOTHING:
    309 		break;
    310 	default:
    311 		out(O_DIE,
    312 		    "internal error: tree_free unexpected nodetype: %d",
    313 		    root->t);
    314 		/*NOTREACHED*/
    315 	}
    316 	alloc_xfree((char *)root, nodesize(root->t, root));
    317 }
    318 
    319 static int
    320 tree_treecmp(struct node *np1, struct node *np2, enum nodetype t,
    321 	    lut_cmp cmp_func)
    322 {
    323 	if (np1 == NULL || np2 == NULL)
    324 		return (0);
    325 
    326 	if (np1->t != np2->t)
    327 		return (1);
    328 
    329 	ASSERT(cmp_func != NULL);
    330 
    331 	if (np1->t == t)
    332 		return ((*cmp_func)(np1, np2));
    333 
    334 	switch (np1->t) {
    335 	case T_NAME:
    336 		if (tree_treecmp(np1->u.name.child, np2->u.name.child, t,
    337 		    cmp_func))
    338 			return (1);
    339 		return (tree_treecmp(np1->u.name.next, np2->u.name.next, t,
    340 		    cmp_func));
    341 		/*NOTREACHED*/
    342 		break;
    343 	case T_FUNC:
    344 		return (tree_treecmp(np1->u.func.arglist, np2->u.func.arglist,
    345 		    t, cmp_func));
    346 		/*NOTREACHED*/
    347 		break;
    348 	case T_AND:
    349 	case T_OR:
    350 	case T_EQ:
    351 	case T_NE:
    352 	case T_ADD:
    353 	case T_DIV:
    354 	case T_MOD:
    355 	case T_MUL:
    356 	case T_SUB:
    357 	case T_LT:
    358 	case T_LE:
    359 	case T_GT:
    360 	case T_GE:
    361 	case T_BITAND:
    362 	case T_BITOR:
    363 	case T_BITXOR:
    364 	case T_BITNOT:
    365 	case T_LSHIFT:
    366 	case T_RSHIFT:
    367 	case T_NVPAIR:
    368 	case T_ASSIGN:
    369 	case T_CONDIF:
    370 	case T_CONDELSE:
    371 	case T_LIST:
    372 		if (tree_treecmp(np1->u.expr.left, np2->u.expr.left, t,
    373 		    cmp_func))
    374 			return (1);
    375 		return (tree_treecmp(np1->u.expr.right, np2->u.expr.right, t,
    376 		    cmp_func));
    377 		/*NOTREACHED*/
    378 		break;
    379 	case T_EVENT:
    380 		if (tree_treecmp(np1->u.event.ename, np2->u.event.ename, t,
    381 		    cmp_func))
    382 			return (1);
    383 		if (tree_treecmp(np1->u.event.epname, np2->u.event.epname, t,
    384 		    cmp_func))
    385 			return (1);
    386 		return (tree_treecmp(np1->u.event.eexprlist,
    387 		    np2->u.event.eexprlist, t, cmp_func));
    388 		/*NOTREACHED*/
    389 		break;
    390 	case T_NOT:
    391 		return (tree_treecmp(np1->u.expr.left, np2->u.expr.left, t,
    392 		    cmp_func));
    393 		/*NOTREACHED*/
    394 		break;
    395 	case T_ARROW:
    396 		if (tree_treecmp(np1->u.arrow.lhs, np2->u.arrow.lhs, t,
    397 		    cmp_func))
    398 			return (1);
    399 		if (tree_treecmp(np1->u.arrow.nnp, np2->u.arrow.nnp, t,
    400 		    cmp_func))
    401 			return (1);
    402 		if (tree_treecmp(np1->u.arrow.knp, np2->u.arrow.knp, t,
    403 		    cmp_func))
    404 			return (1);
    405 		return (tree_treecmp(np1->u.arrow.rhs, np2->u.arrow.rhs, t,
    406 		    cmp_func));
    407 		/*NOTREACHED*/
    408 		break;
    409 	case T_PROP:
    410 	case T_MASK:
    411 		return (tree_treecmp(np1->u.stmt.np, np2->u.stmt.np, t,
    412 		    cmp_func));
    413 		/*NOTREACHED*/
    414 		break;
    415 	case T_FAULT:
    416 	case T_UPSET:
    417 	case T_DEFECT:
    418 	case T_ERROR:
    419 	case T_EREPORT:
    420 	case T_ASRU:
    421 	case T_FRU:
    422 	case T_SERD:
    423 	case T_STAT:
    424 		if (tree_treecmp(np1->u.stmt.np, np2->u.stmt.np, t, cmp_func))
    425 			return (1);
    426 		return (tree_treecmp(np1->u.stmt.nvpairs, np2->u.stmt.nvpairs,
    427 		    t, cmp_func));
    428 		/*NOTREACHED*/
    429 		break;
    430 	case T_TIMEVAL:
    431 	case T_NUM:
    432 	case T_QUOTE:
    433 	case T_GLOBID:
    434 	case T_NOTHING:
    435 		break;
    436 	default:
    437 		out(O_DIE,
    438 		    "internal error: tree_treecmp unexpected nodetype: %d",
    439 		    np1->t);
    440 		/*NOTREACHED*/
    441 		break;
    442 	}
    443 
    444 	return (0);
    445 }
    446 
    447 struct node *
    448 tree_root(struct node *np)
    449 {
    450 	if (np)
    451 		Root = np;
    452 	return (Root);
    453 }
    454 
    455 struct node *
    456 tree_nothing(void)
    457 {
    458 	return (newnode(T_NOTHING, L_nofile, 0));
    459 }
    460 
    461 struct node *
    462 tree_expr(enum nodetype t, struct node *left, struct node *right)
    463 {
    464 	struct node *ret;
    465 
    466 	ASSERTinfo(left != NULL || right != NULL, ptree_nodetype2str(t));
    467 
    468 	ret = newnode(t,
    469 	    (left) ? left->file : right->file,
    470 	    (left) ? left->line : right->line);
    471 
    472 	ret->u.expr.left = left;
    473 	ret->u.expr.right = right;
    474 
    475 	check_expr(ret);
    476 
    477 	return (ret);
    478 }
    479 
    480 /*
    481  * ename_compress -- convert event class name in to more space-efficient form
    482  *
    483  * this routine is called after the parser has completed an "ename", which
    484  * is that part of an event that contains the class name (like ereport.x.y.z).
    485  * after this routine gets done with the ename, two things are true:
    486  *   1. the ename uses only a single struct node
    487  *   2. ename->u.name.s contains the *complete* class name, dots and all,
    488  *      entered into the string table.
    489  *
    490  * so in addition to saving space by using fewer struct nodes, this routine
    491  * allows consumers of the fault tree to assume the ename is a single
    492  * string, rather than a linked list of strings.
    493  */
    494 static struct node *
    495 ename_compress(struct node *ename)
    496 {
    497 	char *buf;
    498 	char *cp;
    499 	int len = 0;
    500 	struct node *np;
    501 
    502 	if (ename == NULL)
    503 		return (ename);
    504 
    505 	ASSERT(ename->t == T_NAME);
    506 
    507 	if (ename->u.name.next == NULL)
    508 		return (ename);	/* no compression to be applied here */
    509 
    510 	for (np = ename; np != NULL; np = np->u.name.next) {
    511 		ASSERT(np->t == T_NAME);
    512 		len++;	/* room for '.' and final '\0' */
    513 		len += strlen(np->u.name.s);
    514 	}
    515 	cp = buf = alloca(len);
    516 	for (np = ename; np != NULL; np = np->u.name.next) {
    517 		ASSERT(np->t == T_NAME);
    518 		if (np != ename)
    519 			*cp++ = '.';
    520 		(void) strcpy(cp, np->u.name.s);
    521 		cp += strlen(cp);
    522 	}
    523 
    524 	ename->u.name.s = stable(buf);
    525 	tree_free(ename->u.name.next);
    526 	ename->u.name.next = NULL;
    527 	ename->u.name.last = ename;
    528 	return (ename);
    529 }
    530 
    531 struct node *
    532 tree_event(struct node *ename, struct node *epname, struct node *eexprlist)
    533 {
    534 	struct node *ret;
    535 
    536 	ASSERT(ename != NULL);
    537 
    538 	ret = newnode(T_EVENT, ename->file, ename->line);
    539 
    540 	ret->u.event.ename = ename_compress(ename);
    541 	ret->u.event.epname = epname;
    542 	ret->u.event.eexprlist = eexprlist;
    543 
    544 	check_event(ret);
    545 
    546 	return (ret);
    547 }
    548 
    549 struct node *
    550 tree_name(const char *s, enum itertype it, const char *file, int line)
    551 {
    552 	struct node *ret = newnode(T_NAME, file, line);
    553 
    554 	ASSERT(s != NULL);
    555 
    556 	stats_counter_bump(Namecount);
    557 	ret->u.name.t = N_UNSPEC;
    558 	ret->u.name.s = stable(s);
    559 	ret->u.name.it = it;
    560 	ret->u.name.last = ret;
    561 
    562 	if (it == IT_ENAME) {
    563 		/* PHASE2, possible optimization: convert to table driven */
    564 		if (s == L_fault)
    565 			ret->u.name.t = N_FAULT;
    566 		else if (s == L_upset)
    567 			ret->u.name.t = N_UPSET;
    568 		else if (s == L_defect)
    569 			ret->u.name.t = N_DEFECT;
    570 		else if (s == L_error)
    571 			ret->u.name.t = N_ERROR;
    572 		else if (s == L_ereport)
    573 			ret->u.name.t = N_EREPORT;
    574 		else if (s == L_serd)
    575 			ret->u.name.t = N_SERD;
    576 		else if (s == L_stat)
    577 			ret->u.name.t = N_STAT;
    578 		else
    579 			outfl(O_ERR, file, line, "unknown class: %s", s);
    580 	}
    581 	return (ret);
    582 }
    583 
    584 struct node *
    585 tree_iname(const char *s, const char *file, int line)
    586 {
    587 	struct node *ret;
    588 	char *ss;
    589 	char *ptr;
    590 
    591 	ASSERT(s != NULL && *s != '\0');
    592 
    593 	ss = STRDUP(s);
    594 
    595 	ptr = &ss[strlen(ss) - 1];
    596 	if (!isdigit(*ptr)) {
    597 		outfl(O_ERR, file, line,
    598 		    "instanced name expected (i.e. \"x0/y1\")");
    599 		FREE(ss);
    600 		return (tree_name(s, IT_NONE, file, line));
    601 	}
    602 	while (ptr > ss && isdigit(*(ptr - 1)))
    603 		ptr--;
    604 
    605 	ret = newnode(T_NAME, file, line);
    606 	stats_counter_bump(Namecount);
    607 	ret->u.name.child = tree_num(ptr, file, line);
    608 	*ptr = '\0';
    609 	ret->u.name.t = N_UNSPEC;
    610 	ret->u.name.s = stable(ss);
    611 	ret->u.name.it = IT_NONE;
    612 	ret->u.name.last = ret;
    613 	FREE(ss);
    614 
    615 	return (ret);
    616 }
    617 
    618 struct node *
    619 tree_globid(const char *s, const char *file, int line)
    620 {
    621 	struct node *ret = newnode(T_GLOBID, file, line);
    622 
    623 	ASSERT(s != NULL);
    624 
    625 	ret->u.globid.s = stable(s);
    626 
    627 	return (ret);
    628 }
    629 
    630 struct node *
    631 tree_name_append(struct node *np1, struct node *np2)
    632 {
    633 	ASSERT(np1 != NULL && np2 != NULL);
    634 
    635 	if (np1->t != T_NAME)
    636 		outfl(O_DIE, np1->file, np1->line,
    637 		    "tree_name_append: internal error (np1 type %d)", np1->t);
    638 	if (np2->t != T_NAME)
    639 		outfl(O_DIE, np2->file, np2->line,
    640 		    "tree_name_append: internal error (np2 type %d)", np2->t);
    641 
    642 	ASSERT(np1->u.name.last != NULL);
    643 
    644 	np1->u.name.last->u.name.next = np2;
    645 	np1->u.name.last = np2;
    646 	return (np1);
    647 }
    648 
    649 /*
    650  * tree_name_repairdash -- repair a class name that contained a dash
    651  *
    652  * this routine is called by the parser when a dash is encountered
    653  * in a class name.  the event protocol allows the dashes but our
    654  * lexer considers them a separate token (arithmetic minus).  an extra
    655  * rule in the parser catches this case and calls this routine to fixup
    656  * the last component of the class name (so far) by constructing the
    657  * new stable entry for a name including the dash.
    658  */
    659 struct node *
    660 tree_name_repairdash(struct node *np, const char *s)
    661 {
    662 	int len;
    663 	char *buf;
    664 
    665 	ASSERT(np != NULL && s != NULL);
    666 
    667 	if (np->t != T_NAME)
    668 		outfl(O_DIE, np->file, np->line,
    669 		    "tree_name_repairdash: internal error (np type %d)",
    670 		    np->t);
    671 
    672 	ASSERT(np->u.name.last != NULL);
    673 
    674 	len = strlen(np->u.name.last->u.name.s) + 1 + strlen(s) + 1;
    675 	buf = MALLOC(len);
    676 	(void) snprintf(buf, len, "%s-%s", np->u.name.last->u.name.s, s);
    677 	np->u.name.last->u.name.s = stable(buf);
    678 	FREE(buf);
    679 	return (np);
    680 }
    681 
    682 struct node *
    683 tree_name_repairdash2(const char *s, struct node *np)
    684 {
    685 	int len;
    686 	char *buf;
    687 
    688 	ASSERT(np != NULL && s != NULL);
    689 
    690 	if (np->t != T_NAME)
    691 		outfl(O_DIE, np->file, np->line,
    692 		    "tree_name_repairdash: internal error (np type %d)",
    693 		    np->t);
    694 
    695 	ASSERT(np->u.name.last != NULL);
    696 
    697 	len = strlen(np->u.name.last->u.name.s) + 1 + strlen(s) + 1;
    698 	buf = MALLOC(len);
    699 	(void) snprintf(buf, len, "%s-%s", s, np->u.name.last->u.name.s);
    700 	np->u.name.last->u.name.s = stable(buf);
    701 	FREE(buf);
    702 	return (np);
    703 }
    704 
    705 struct node *
    706 tree_name_iterator(struct node *np1, struct node *np2)
    707 {
    708 	ASSERT(np1 != NULL);
    709 	ASSERT(np2 != NULL);
    710 	ASSERTinfo(np1->t == T_NAME, ptree_nodetype2str(np1->t));
    711 
    712 	np1->u.name.child = np2;
    713 
    714 	check_name_iterator(np1);
    715 
    716 	return (np1);
    717 }
    718 
    719 struct node *
    720 tree_timeval(const char *s, const char *suffix, const char *file, int line)
    721 {
    722 	struct node *ret = newnode(T_TIMEVAL, file, line);
    723 	const unsigned long long *ullp;
    724 
    725 	ASSERT(s != NULL);
    726 	ASSERT(suffix != NULL);
    727 
    728 	if ((ullp = lex_s2ullp_lut_lookup(Timesuffixlut, suffix)) == NULL) {
    729 		outfl(O_ERR, file, line,
    730 		    "unrecognized number suffix: %s", suffix);
    731 		/* still construct a valid timeval node so parsing continues */
    732 		ret->u.ull = 1;
    733 	} else {
    734 		ret->u.ull = (unsigned long long)strtoul(s, NULL, 0) * *ullp;
    735 	}
    736 
    737 	return (ret);
    738 }
    739 
    740 struct node *
    741 tree_num(const char *s, const char *file, int line)
    742 {
    743 	struct node *ret = newnode(T_NUM, file, line);
    744 
    745 	ret->u.ull = (unsigned long long)strtoul(s, NULL, 0);
    746 	return (ret);
    747 }
    748 
    749 struct node *
    750 tree_quote(const char *s, const char *file, int line)
    751 {
    752 	struct node *ret = newnode(T_QUOTE, file, line);
    753 
    754 	ret->u.quote.s = stable(s);
    755 	return (ret);
    756 }
    757 
    758 struct node *
    759 tree_func(const char *s, struct node *np, const char *file, int line)
    760 {
    761 	struct node *ret = newnode(T_FUNC, file, line);
    762 	const char *ptr;
    763 
    764 	ret->u.func.s = s;
    765 	ret->u.func.arglist = np;
    766 
    767 	check_func(ret);
    768 
    769 	/*
    770 	 * keep track of the properties we're interested in so we can ignore the
    771 	 * rest
    772 	 */
    773 	if (strcmp(s, L_confprop) == 0 || strcmp(s, L_confprop_defined) == 0) {
    774 		ptr = stable(np->u.expr.right->u.quote.s);
    775 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    776 	} else if (strcmp(s, L_is_connected) == 0) {
    777 		ptr = stable("connected");
    778 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    779 		ptr = stable("CONNECTED");
    780 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    781 	} else if (strcmp(s, L_is_type) == 0) {
    782 		ptr = stable("type");
    783 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    784 		ptr = stable("TYPE");
    785 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    786 	} else if (strcmp(s, L_is_on) == 0) {
    787 		ptr = stable("on");
    788 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    789 		ptr = stable("ON");
    790 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    791 	}
    792 
    793 	return (ret);
    794 }
    795 
    796 /*
    797  * given a list from a prop or mask statement or a function argument,
    798  * convert all iterators to explicit iterators by inventing appropriate
    799  * iterator names.
    800  */
    801 static void
    802 make_explicit(struct node *np, int eventonly)
    803 {
    804 	struct node *pnp;	/* component of pathname */
    805 	struct node *pnp2;
    806 	int count;
    807 	static size_t namesz;
    808 
    809 	if (Newname == NULL) {
    810 		namesz = 200;
    811 		Newname = MALLOC(namesz);
    812 	}
    813 
    814 	if (np == NULL)
    815 		return;		/* all done */
    816 
    817 	switch (np->t) {
    818 		case T_ASSIGN:
    819 		case T_CONDIF:
    820 		case T_CONDELSE:
    821 		case T_NE:
    822 		case T_EQ:
    823 		case T_LT:
    824 		case T_LE:
    825 		case T_GT:
    826 		case T_GE:
    827 		case T_BITAND:
    828 		case T_BITOR:
    829 		case T_BITXOR:
    830 		case T_BITNOT:
    831 		case T_LSHIFT:
    832 		case T_RSHIFT:
    833 		case T_LIST:
    834 		case T_AND:
    835 		case T_OR:
    836 		case T_NOT:
    837 		case T_ADD:
    838 		case T_SUB:
    839 		case T_MUL:
    840 		case T_DIV:
    841 		case T_MOD:
    842 			make_explicit(np->u.expr.left, eventonly);
    843 			make_explicit(np->u.expr.right, eventonly);
    844 			break;
    845 
    846 		case T_EVENT:
    847 			make_explicit(np->u.event.epname, 0);
    848 			make_explicit(np->u.event.eexprlist, 1);
    849 			break;
    850 
    851 		case T_FUNC:
    852 			make_explicit(np->u.func.arglist, eventonly);
    853 			break;
    854 
    855 		case T_NAME:
    856 			if (eventonly)
    857 				return;
    858 			for (pnp = np; pnp != NULL; pnp = pnp->u.name.next)
    859 				if (pnp->u.name.child == NULL) {
    860 					/*
    861 					 * found implicit iterator.  convert
    862 					 * it to an explicit iterator by
    863 					 * using the name of the component
    864 					 * appended with '#' and the number
    865 					 * of times we've seen this same
    866 					 * component name in this path so far.
    867 					 */
    868 					count = 0;
    869 					for (pnp2 = np; pnp2 != NULL;
    870 					    pnp2 = pnp2->u.name.next)
    871 						if (pnp2 == pnp)
    872 							break;
    873 						else if (pnp2->u.name.s ==
    874 						    pnp->u.name.s)
    875 							count++;
    876 
    877 					if (namesz < strlen(pnp->u.name.s) +
    878 					    100) {
    879 						namesz = strlen(pnp->u.name.s) +
    880 						    100;
    881 						FREE(Newname);
    882 						Newname = MALLOC(namesz);
    883 					}
    884 					/*
    885 					 * made up interator name is:
    886 					 *	name#ordinal
    887 					 * or
    888 					 *	name##ordinal
    889 					 * the first one is used for vertical
    890 					 * expansion, the second for horizontal.
    891 					 * either way, the '#' embedded in
    892 					 * the name makes it impossible to
    893 					 * collide with an actual iterator
    894 					 * given to us in the eversholt file.
    895 					 */
    896 					(void) snprintf(Newname, namesz,
    897 					    "%s#%s%d", pnp->u.name.s,
    898 					    (pnp->u.name.it == IT_HORIZONTAL) ?
    899 					    "#" : "", count);
    900 
    901 					pnp->u.name.child = tree_name(Newname,
    902 					    IT_NONE, pnp->file, pnp->line);
    903 					pnp->u.name.childgen = 1;
    904 				}
    905 			break;
    906 	}
    907 }
    908 
    909 struct node *
    910 tree_pname(struct node *np)
    911 {
    912 	make_explicit(np, 0);
    913 	return (np);
    914 }
    915 
    916 struct node *
    917 tree_arrow(struct node *lhs, struct node *nnp, struct node *knp,
    918     struct node *rhs)
    919 {
    920 	struct node *ret;
    921 
    922 	ASSERT(lhs != NULL || rhs != NULL);
    923 
    924 	ret = newnode(T_ARROW,
    925 	    (lhs) ? lhs->file : rhs->file,
    926 	    (lhs) ? lhs->line : rhs->line);
    927 
    928 	ret->u.arrow.lhs = lhs;
    929 	ret->u.arrow.nnp = nnp;
    930 	ret->u.arrow.knp = knp;
    931 	ret->u.arrow.rhs = rhs;
    932 
    933 	make_explicit(lhs, 0);
    934 	make_explicit(rhs, 0);
    935 
    936 	check_arrow(ret);
    937 
    938 	return (ret);
    939 }
    940 
    941 static struct lut *
    942 nvpair2lut(struct node *np, struct lut *lutp, enum nodetype t)
    943 {
    944 	if (np) {
    945 		if (np->t == T_NVPAIR) {
    946 			ASSERTeq(np->u.expr.left->t, T_NAME,
    947 			    ptree_nodetype2str);
    948 			check_stmt_allowed_properties(t, np, lutp);
    949 			lutp = tree_s2np_lut_add(lutp,
    950 			    np->u.expr.left->u.name.s, np->u.expr.right);
    951 		} else if (np->t == T_LIST) {
    952 			lutp = nvpair2lut(np->u.expr.left, lutp, t);
    953 			lutp = nvpair2lut(np->u.expr.right, lutp, t);
    954 		} else
    955 			outfl(O_DIE, np->file, np->line,
    956 			    "internal error: nvpair2lut type %s",
    957 			    ptree_nodetype2str(np->t));
    958 	}
    959 
    960 	return (lutp);
    961 }
    962 
    963 struct lut *
    964 tree_s2np_lut_add(struct lut *root, const char *s, struct node *np)
    965 {
    966 	return (lut_add(root, (void *)s, (void *)np, NULL));
    967 }
    968 
    969 struct node *
    970 tree_s2np_lut_lookup(struct lut *root, const char *s)
    971 {
    972 	return (struct node *)lut_lookup(root, (void *)s, NULL);
    973 }
    974 
    975 struct lut *
    976 tree_name2np_lut_add(struct lut *root, struct node *namep, struct node *np)
    977 {
    978 	return (lut_add(root, (void *)namep, (void *)np,
    979 	    (lut_cmp)tree_namecmp));
    980 }
    981 
    982 struct node *
    983 tree_name2np_lut_lookup(struct lut *root, struct node *namep)
    984 {
    985 	return (struct node *)
    986 	    lut_lookup(root, (void *)namep, (lut_cmp)tree_namecmp);
    987 }
    988 
    989 struct node *
    990 tree_name2np_lut_lookup_name(struct lut *root, struct node *namep)
    991 {
    992 	return (struct node *)
    993 	    lut_lookup_lhs(root, (void *)namep, (lut_cmp)tree_namecmp);
    994 }
    995 
    996 struct lut *
    997 tree_event2np_lut_add(struct lut *root, struct node *enp, struct node *np)
    998 {
    999 	return (lut_add(root, (void *)enp, (void *)np, (lut_cmp)tree_eventcmp));
   1000 }
   1001 
   1002 struct node *
   1003 tree_event2np_lut_lookup(struct lut *root, struct node *enp)
   1004 {
   1005 	return ((struct node *)
   1006 	    lut_lookup(root, (void *)enp, (lut_cmp)tree_eventcmp));
   1007 }
   1008 
   1009 struct node *
   1010 tree_event2np_lut_lookup_event(struct lut *root, struct node *enp)
   1011 {
   1012 	return ((struct node *)
   1013 	    lut_lookup_lhs(root, (void *)enp, (lut_cmp)tree_eventcmp));
   1014 }
   1015 
   1016 static struct node *
   1017 dodecl(enum nodetype t, const char *file, int line,
   1018     struct node *np, struct node *nvpairs, struct lut **lutpp,
   1019     struct stats *countp, int justpath)
   1020 {
   1021 	struct node *ret;
   1022 	struct node *decl;
   1023 
   1024 	/* allocate parse tree node */
   1025 	ret = newnode(t, file, line);
   1026 	ret->u.stmt.np = np;
   1027 	ret->u.stmt.nvpairs = nvpairs;
   1028 
   1029 	/*
   1030 	 * the global lut pointed to by lutpp (Faults, Defects, Upsets,
   1031 	 * Errors, Ereports, Serds, FRUs, or ASRUs) keeps the first decl.
   1032 	 * if this isn't the first declr, we merge the
   1033 	 * nvpairs into the first decl so we have a
   1034 	 * merged table to look up properties from.
   1035 	 * if this is the first time we've seen this fault,
   1036 	 * we add it to the global lut and start lutp
   1037 	 * off with any nvpairs from this declaration statement.
   1038 	 */
   1039 	if (justpath && (decl = tree_name2np_lut_lookup(*lutpp, np)) == NULL) {
   1040 		/* this is the first time name is declared */
   1041 		stats_counter_bump(countp);
   1042 		*lutpp = tree_name2np_lut_add(*lutpp, np, ret);
   1043 		ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, t);
   1044 	} else if (!justpath &&
   1045 	    (decl = tree_event2np_lut_lookup(*lutpp, np)) == NULL) {
   1046 		/* this is the first time event is declared */
   1047 		stats_counter_bump(countp);
   1048 		*lutpp = tree_event2np_lut_add(*lutpp, np, ret);
   1049 		ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, t);
   1050 	} else {
   1051 		/* was declared before, just add new nvpairs to its lutp */
   1052 		decl->u.stmt.lutp = nvpair2lut(nvpairs, decl->u.stmt.lutp, t);
   1053 	}
   1054 
   1055 	return (ret);
   1056 }
   1057 
   1058 /*ARGSUSED*/
   1059 static void
   1060 update_serd_refstmt(void *lhs, void *rhs, void *arg)
   1061 {
   1062 	struct node *serd;
   1063 
   1064 	ASSERT(rhs != NULL);
   1065 
   1066 	serd = tree_s2np_lut_lookup(((struct node *)rhs)->u.stmt.lutp,
   1067 	    L_engine);
   1068 	if (serd == NULL)
   1069 		return;
   1070 
   1071 	ASSERT(serd->t == T_EVENT);
   1072 	if (arg != NULL && tree_eventcmp(serd, (struct node *)arg) != 0)
   1073 		return;
   1074 
   1075 	serd = tree_event2np_lut_lookup(SERDs, serd);
   1076 	if (serd != NULL)
   1077 		serd->u.stmt.flags |= STMT_REF;
   1078 }
   1079 
   1080 struct node *
   1081 tree_decl(enum nodetype t, struct node *np, struct node *nvpairs,
   1082     const char *file, int line)
   1083 {
   1084 	struct node *decl;
   1085 	struct node *ret;
   1086 
   1087 	ASSERT(np != NULL);
   1088 
   1089 	check_type_iterator(np);
   1090 
   1091 	switch (t) {
   1092 	case T_EVENT:
   1093 		/* determine the type of event being declared */
   1094 		ASSERT(np->u.event.ename->t == T_NAME);
   1095 		switch (np->u.event.ename->u.name.t) {
   1096 		case N_FAULT:
   1097 			ret = dodecl(T_FAULT, file, line, np, nvpairs,
   1098 			    &Faults, Faultcount, 0);
   1099 
   1100 			/* increment serd statement reference */
   1101 			decl = tree_event2np_lut_lookup(Faults, np);
   1102 			update_serd_refstmt(NULL, decl, NULL);
   1103 			break;
   1104 
   1105 		case N_UPSET:
   1106 			ret = dodecl(T_UPSET, file, line, np, nvpairs,
   1107 			    &Upsets, Upsetcount, 0);
   1108 
   1109 			/* increment serd statement reference */
   1110 			decl = tree_event2np_lut_lookup(Upsets, np);
   1111 			update_serd_refstmt(NULL, decl, NULL);
   1112 			break;
   1113 
   1114 		case N_DEFECT:
   1115 			ret = dodecl(T_DEFECT, file, line, np, nvpairs,
   1116 			    &Defects, Defectcount, 0);
   1117 
   1118 			/* increment serd statement reference */
   1119 			decl = tree_event2np_lut_lookup(Defects, np);
   1120 			update_serd_refstmt(NULL, decl, NULL);
   1121 			break;
   1122 
   1123 		case N_ERROR:
   1124 			ret = dodecl(T_ERROR, file, line, np, nvpairs,
   1125 			    &Errors, Errorcount, 0);
   1126 			break;
   1127 
   1128 		case N_EREPORT:
   1129 			ret = dodecl(T_EREPORT, file, line, np, nvpairs,
   1130 			    &Ereports, Ereportcount, 0);
   1131 			/*
   1132 			 * Keep a lut of just the enames, so that the DE
   1133 			 * can subscribe to a uniqified list of event
   1134 			 * classes.
   1135 			 */
   1136 			Ereportenames =
   1137 			    tree_name2np_lut_add(Ereportenames,
   1138 			    np->u.event.ename, np);
   1139 
   1140 			/*
   1141 			 * Keep a lut of the enames (event classes) to
   1142 			 * silently discard if we can't find a matching
   1143 			 * configuration node when an ereport of of a given
   1144 			 * class is received.  Such events are declaired
   1145 			 * with 'discard_if_config_unknown=1'.
   1146 			 */
   1147 			if (tree_s2np_lut_lookup(ret->u.stmt.lutp,
   1148 			    L_discard_if_config_unknown)) {
   1149 				Ereportenames_discard = lut_add(
   1150 				    Ereportenames_discard,
   1151 				    (void *)np->u.event.ename->u.name.s,
   1152 				    (void *)np->u.event.ename->u.name.s, NULL);
   1153 			}
   1154 			break;
   1155 
   1156 		default:
   1157 			outfl(O_ERR, file, line,
   1158 			    "tree_decl: internal error, event name type %s",
   1159 			    ptree_nametype2str(np->u.event.ename->u.name.t));
   1160 		}
   1161 		break;
   1162 
   1163 	case T_ENGINE:
   1164 		/* determine the type of engine being declared */
   1165 		ASSERT(np->u.event.ename->t == T_NAME);
   1166 		switch (np->u.event.ename->u.name.t) {
   1167 		case N_SERD:
   1168 			ret = dodecl(T_SERD, file, line, np, nvpairs,
   1169 			    &SERDs, SERDcount, 0);
   1170 			lut_walk(Upsets, update_serd_refstmt, np);
   1171 			break;
   1172 
   1173 		case N_STAT:
   1174 			ret = dodecl(T_STAT, file, line, np, nvpairs,
   1175 			    &STATs, STATcount, 0);
   1176 			break;
   1177 
   1178 		default:
   1179 			outfl(O_ERR, file, line,
   1180 			    "tree_decl: internal error, engine name type %s",
   1181 			    ptree_nametype2str(np->u.event.ename->u.name.t));
   1182 		}
   1183 		break;
   1184 	case T_ASRU:
   1185 		ret = dodecl(T_ASRU, file, line, np, nvpairs,
   1186 		    &ASRUs, ASRUcount, 1);
   1187 		break;
   1188 
   1189 	case T_FRU:
   1190 		ret = dodecl(T_FRU, file, line, np, nvpairs,
   1191 		    &FRUs, FRUcount, 1);
   1192 		break;
   1193 
   1194 	case T_CONFIG:
   1195 		/*
   1196 		 * config statements are different from above: they
   1197 		 * are not merged at all (until the configuration cache
   1198 		 * code does its own style of merging.  and the properties
   1199 		 * are a free-for-all -- we don't check for allowed or
   1200 		 * required config properties.
   1201 		 */
   1202 		ret = newnode(T_CONFIG, file, line);
   1203 		ret->u.stmt.np = np;
   1204 		ret->u.stmt.nvpairs = nvpairs;
   1205 		ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, T_CONFIG);
   1206 
   1207 		if (lut_lookup(Configs, np, (lut_cmp)tree_namecmp) == NULL)
   1208 			stats_counter_bump(Configcount);
   1209 
   1210 		Configs = lut_add(Configs, (void *)np, (void *)ret, NULL);
   1211 		break;
   1212 
   1213 	default:
   1214 		out(O_DIE, "tree_decl: internal error, type %s",
   1215 		    ptree_nodetype2str(t));
   1216 	}
   1217 
   1218 	return (ret);
   1219 }
   1220 
   1221 /* keep backpointers in arrows to the prop they belong to (used for scoping) */
   1222 static void
   1223 set_arrow_prop(struct node *prop, struct node *np)
   1224 {
   1225 	if (np == NULL)
   1226 		return;
   1227 
   1228 	if (np->t == T_ARROW) {
   1229 		np->u.arrow.prop = prop;
   1230 		set_arrow_prop(prop, np->u.arrow.lhs);
   1231 		/*
   1232 		 * no need to recurse right or handle T_LIST since
   1233 		 * T_ARROWs always cascade left and are at the top
   1234 		 * of the parse tree.  (you can see this in the rule
   1235 		 * for "propbody" in escparse.y.)
   1236 		 */
   1237 	}
   1238 }
   1239 
   1240 struct node *
   1241 tree_stmt(enum nodetype t, struct node *np, const char *file, int line)
   1242 {
   1243 	struct node *ret = newnode(t, file, line);
   1244 	struct node *pp;
   1245 	int inlist = 0;
   1246 
   1247 	ret->u.stmt.np = np;
   1248 
   1249 	switch (t) {
   1250 	case T_PROP:
   1251 		check_proplists(t, np);
   1252 		check_propnames(t, np, 0, 0);
   1253 		check_propscope(np);
   1254 		set_arrow_prop(ret, np);
   1255 
   1256 		for (pp = Props; pp; pp = pp->u.stmt.next) {
   1257 			if (tree_treecmp(pp, ret, T_NAME,
   1258 			    (lut_cmp)tree_namecmp) == 0) {
   1259 				inlist = 1;
   1260 				break;
   1261 			}
   1262 		}
   1263 		if (inlist == 0)
   1264 			stats_counter_bump(Propcount);
   1265 
   1266 		/* "Props" is a linked list of all prop statements */
   1267 		if (Lastprops)
   1268 			Lastprops->u.stmt.next = ret;
   1269 		else
   1270 			Props = ret;
   1271 		Lastprops = ret;
   1272 		break;
   1273 
   1274 	case T_MASK:
   1275 		check_proplists(t, np);
   1276 		check_propnames(t, np, 0, 0);
   1277 		check_propscope(np);
   1278 		set_arrow_prop(ret, np);
   1279 
   1280 		for (pp = Masks; pp; pp = pp->u.stmt.next) {
   1281 			if (tree_treecmp(pp, ret, T_NAME,
   1282 			    (lut_cmp)tree_namecmp) == 0) {
   1283 				inlist = 1;
   1284 				break;
   1285 			}
   1286 		}
   1287 		if (inlist == 0)
   1288 			stats_counter_bump(Maskcount);
   1289 
   1290 		/* "Masks" is a linked list of all mask statements */
   1291 		if (Lastmasks)
   1292 			Lastmasks->u.stmt.next = ret;
   1293 		else
   1294 			Masks = ret;
   1295 		Lastmasks = ret;
   1296 		stats_counter_bump(Maskcount);
   1297 		break;
   1298 
   1299 	default:
   1300 		outfl(O_DIE, np->file, np->line,
   1301 		    "tree_stmt: internal error (t %d)", t);
   1302 	}
   1303 
   1304 	return (ret);
   1305 }
   1306 
   1307 void
   1308 tree_report()
   1309 {
   1310 	/*
   1311 	 * The only declarations with required properties
   1312 	 * currently are faults and serds. Make sure the
   1313 	 * the declarations have the required properties.
   1314 	 */
   1315 	lut_walk(Faults, (lut_cb)check_required_props, (void *)T_FAULT);
   1316 	lut_walk(Upsets, (lut_cb)check_required_props, (void *)T_UPSET);
   1317 	lut_walk(Errors, (lut_cb)check_required_props, (void *)T_ERROR);
   1318 	lut_walk(Ereports, (lut_cb)check_required_props, (void *)T_EREPORT);
   1319 	lut_walk(SERDs, (lut_cb)check_required_props, (void *)T_SERD);
   1320 	lut_walk(STATs, (lut_cb)check_required_props, (void *)T_STAT);
   1321 
   1322 	/*
   1323 	 * we do this now rather than while building the parse
   1324 	 * tree because it is inconvenient for the user if we
   1325 	 * require SERD engines to be declared before used in
   1326 	 * an upset "engine" property.
   1327 	 */
   1328 	lut_walk(Faults, (lut_cb)check_refcount, (void *)T_FAULT);
   1329 	lut_walk(Faults, (lut_cb)check_upset_engine, (void *)T_FAULT);
   1330 	lut_walk(Defects, (lut_cb)check_upset_engine, (void *)T_DEFECT);
   1331 	lut_walk(Upsets, (lut_cb)check_upset_engine, (void *)T_UPSET);
   1332 	lut_walk(Upsets, (lut_cb)check_refcount, (void *)T_UPSET);
   1333 	lut_walk(Errors, (lut_cb)check_refcount, (void *)T_ERROR);
   1334 	lut_walk(Ereports, (lut_cb)check_refcount, (void *)T_EREPORT);
   1335 	lut_walk(SERDs, (lut_cb)check_refcount, (void *)T_SERD);
   1336 
   1337 	/* check for cycles */
   1338 	lut_walk(Errors, (lut_cb)check_cycle, (void *)0);
   1339 }
   1340 
   1341 /* compare two T_NAMES by only looking at components, not iterators */
   1342 int
   1343 tree_namecmp(struct node *np1, struct node *np2)
   1344 {
   1345 	ASSERT(np1 != NULL);
   1346 	ASSERT(np2 != NULL);
   1347 	ASSERTinfo(np1->t == T_NAME, ptree_nodetype2str(np1->t));
   1348 	ASSERTinfo(np2->t == T_NAME, ptree_nodetype2str(np1->t));
   1349 
   1350 	while (np1 && np2 && np1->u.name.s == np2->u.name.s) {
   1351 		np1 = np1->u.name.next;
   1352 		np2 = np2->u.name.next;
   1353 	}
   1354 	if (np1 == NULL)
   1355 		if (np2 == NULL)
   1356 			return (0);
   1357 		else
   1358 			return (-1);
   1359 	else if (np2 == NULL)
   1360 		return (1);
   1361 	else
   1362 		return (np2->u.name.s - np1->u.name.s);
   1363 }
   1364 
   1365 int
   1366 tree_eventcmp(struct node *np1, struct node *np2)
   1367 {
   1368 	int ret;
   1369 
   1370 	ASSERT(np1 != NULL);
   1371 	ASSERT(np2 != NULL);
   1372 	ASSERTinfo(np1->t == T_EVENT, ptree_nodetype2str(np1->t));
   1373 	ASSERTinfo(np2->t == T_EVENT, ptree_nodetype2str(np2->t));
   1374 
   1375 	if ((ret = tree_namecmp(np1->u.event.ename,
   1376 	    np2->u.event.ename)) == 0) {
   1377 			if (np1->u.event.epname == NULL &&
   1378 			    np2->u.event.epname == NULL)
   1379 				return (0);
   1380 			else if (np1->u.event.epname == NULL)
   1381 				return (-1);
   1382 			else if (np2->u.event.epname == NULL)
   1383 				return (1);
   1384 			else
   1385 				return tree_namecmp(np1->u.event.epname,
   1386 				    np2->u.event.epname);
   1387 	} else
   1388 	return (ret);
   1389 }
   1390