xref: /onnv-gate/usr/src/cmd/fm/modules/common/eversholt/itree.c (revision 4436:35b72f77cdd9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51717Swesolows  * Common Development and Distribution License (the "License").
61717Swesolows  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211717Swesolows 
220Sstevel@tonic-gate /*
23*4436Sstephh  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  *
260Sstevel@tonic-gate  * itree.c -- instance tree creation and manipulation
270Sstevel@tonic-gate  *
280Sstevel@tonic-gate  * this module provides the instance tree
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <stdio.h>
340Sstevel@tonic-gate #include <ctype.h>
350Sstevel@tonic-gate #include <string.h>
360Sstevel@tonic-gate #include <strings.h>
370Sstevel@tonic-gate #include "alloc.h"
380Sstevel@tonic-gate #include "out.h"
390Sstevel@tonic-gate #include "stable.h"
400Sstevel@tonic-gate #include "literals.h"
410Sstevel@tonic-gate #include "lut.h"
420Sstevel@tonic-gate #include "tree.h"
430Sstevel@tonic-gate #include "ptree.h"
440Sstevel@tonic-gate #include "itree.h"
450Sstevel@tonic-gate #include "ipath.h"
461414Scindi #include "iexpr.h"
470Sstevel@tonic-gate #include "eval.h"
480Sstevel@tonic-gate #include "config.h"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate  * struct info contains the state we keep when expanding a prop statement
520Sstevel@tonic-gate  * as part of constructing the instance tree.  state kept in struct info
530Sstevel@tonic-gate  * is the non-recursive stuff -- the stuff that doesn't need to be on
540Sstevel@tonic-gate  * the stack.  the rest of the state that is passed between all the
550Sstevel@tonic-gate  * mutually recursive functions, is required to be on the stack since
560Sstevel@tonic-gate  * we need to backtrack and recurse as we do the instance tree construction.
570Sstevel@tonic-gate  */
580Sstevel@tonic-gate struct info {
590Sstevel@tonic-gate 	struct lut *lut;
600Sstevel@tonic-gate 	struct node *anp;	/* arrow np */
610Sstevel@tonic-gate 	struct lut *ex;		/* dictionary of explicit iterators */
620Sstevel@tonic-gate 	struct config *croot;
630Sstevel@tonic-gate } Ninfo;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate  * struct wildcardinfo is used to track wildcarded portions of paths.
670Sstevel@tonic-gate  *
680Sstevel@tonic-gate  * for example, if the epname of an event is "c/d" and the path "a/b/c/d"
690Sstevel@tonic-gate  * exists, the wildcard path ewname is filled in with the path "a/b".  when
700Sstevel@tonic-gate  * matching is done, epname is temporarily replaced with the concatenation
71*4436Sstephh  * of ewname and epname.
720Sstevel@tonic-gate  *
730Sstevel@tonic-gate  * a linked list of these structs is used to track the expansion of each
740Sstevel@tonic-gate  * event node as it is processed in vmatch() --> vmatch_event() calls.
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate struct wildcardinfo {
770Sstevel@tonic-gate 	struct node *nptop;		/* event node fed to vmatch */
780Sstevel@tonic-gate 	struct node *oldepname;		/* epname without the wildcard part */
79*4436Sstephh 	struct node *ewname;		/* wildcard path */
800Sstevel@tonic-gate 	struct wildcardinfo *next;
810Sstevel@tonic-gate };
820Sstevel@tonic-gate 
83*4436Sstephh static struct wildcardinfo *wcproot = NULL;
84*4436Sstephh 
85*4436Sstephh static void vmatch(struct info *infop, struct node *np, struct node *lnp,
86*4436Sstephh     struct node *anp);
870Sstevel@tonic-gate static void hmatch(struct info *infop, struct node *np, struct node *nextnp);
880Sstevel@tonic-gate static void itree_pbubble(int flags, struct bubble *bp);
891865Sdilpreet static void itree_pruner(void *left, void *right, void *arg);
900Sstevel@tonic-gate static void itree_destructor(void *left, void *right, void *arg);
910Sstevel@tonic-gate static int itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
920Sstevel@tonic-gate     struct node *toev, struct lut *ex);
930Sstevel@tonic-gate static void itree_free_arrowlists(struct bubble *bubp, int arrows_too);
941865Sdilpreet static void itree_prune_arrowlists(struct bubble *bubp);
950Sstevel@tonic-gate static void arrow_add_within(struct arrow *ap, struct node *xpr);
96*4436Sstephh static struct arrow *itree_add_arrow(struct node *apnode,
97*4436Sstephh     struct node *fromevent, struct node *toevent, struct lut *ex);
98*4436Sstephh static struct event *find_or_add_event(struct info *infop, struct node *np);
99*4436Sstephh static void add_arrow(struct bubble *bp, struct arrow *ap);
1000Sstevel@tonic-gate static struct constraintlist *itree_add_constraint(struct arrow *arrowp,
1010Sstevel@tonic-gate     struct node *c);
1020Sstevel@tonic-gate static struct bubble *itree_add_bubble(struct event *eventp,
1030Sstevel@tonic-gate     enum bubbletype btype, int nork, int gen);
1040Sstevel@tonic-gate static void itree_free_bubble(struct bubble *freeme);
1050Sstevel@tonic-gate static void itree_free_constraints(struct arrow *ap);
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate  * the following struct contains the state we build up during
1090Sstevel@tonic-gate  * vertical and horizontal expansion so that generate()
1100Sstevel@tonic-gate  * has everything it needs to construct the appropriate arrows.
1110Sstevel@tonic-gate  * after setting up the state by calling:
1120Sstevel@tonic-gate  *	generate_arrownp()
1130Sstevel@tonic-gate  *	generate_nork()
1140Sstevel@tonic-gate  *	generate_new()
1150Sstevel@tonic-gate  *	generate_from()
1160Sstevel@tonic-gate  *	generate_to()
1170Sstevel@tonic-gate  * the actual arrow generation is done by calling:
1180Sstevel@tonic-gate  *	generate()
1190Sstevel@tonic-gate  */
1200Sstevel@tonic-gate static struct {
1210Sstevel@tonic-gate 	int generation;		/* generation number of arrow set */
1220Sstevel@tonic-gate 	struct node *arrownp;	/* top-level parse tree for arrow */
1230Sstevel@tonic-gate 	int n;			/* n value associated with arrow */
1240Sstevel@tonic-gate 	int k;			/* k value associated with arrow */
1250Sstevel@tonic-gate 	struct node *fromnp;	/* left-hand-side event in parse tree */
1260Sstevel@tonic-gate 	struct node *tonp;	/* right-hand-side event in parse tree */
1270Sstevel@tonic-gate 	struct event *frome;	/* left-hand-side event in instance tree */
1280Sstevel@tonic-gate 	struct event *toe;	/* right-hand-side event in instance tree */
1290Sstevel@tonic-gate 	struct bubble *frombp;	/* bubble arrow comes from */
1300Sstevel@tonic-gate 	struct bubble *tobp;	/* bubble arrow goes to */
1310Sstevel@tonic-gate } G;
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate static void
1340Sstevel@tonic-gate generate_arrownp(struct node *arrownp)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	G.arrownp = arrownp;
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate static void
1400Sstevel@tonic-gate generate_nork(int n, int k)
1410Sstevel@tonic-gate {
1420Sstevel@tonic-gate 	G.n = n;
1430Sstevel@tonic-gate 	G.k = k;
1440Sstevel@tonic-gate }
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate static void
1470Sstevel@tonic-gate generate_new(void)
1480Sstevel@tonic-gate {
1490Sstevel@tonic-gate 	G.generation++;
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate static void
153*4436Sstephh generate_from(struct node *fromeventnp)
1540Sstevel@tonic-gate {
155*4436Sstephh 	G.frombp = NULL;
1560Sstevel@tonic-gate 	G.fromnp = fromeventnp;
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate static void
160*4436Sstephh generate_to(struct node *toeventnp)
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate 	G.tonp = toeventnp;
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate static void
166*4436Sstephh generate(struct info *infop)
1670Sstevel@tonic-gate {
168*4436Sstephh 	struct arrow *arrowp;
169*4436Sstephh 
1700Sstevel@tonic-gate 	ASSERT(G.arrownp != NULL);
1710Sstevel@tonic-gate 	ASSERT(G.fromnp != NULL);
1720Sstevel@tonic-gate 	ASSERT(G.tonp != NULL);
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL, "        Arrow \"");
1750Sstevel@tonic-gate 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp);
1760Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL, "\" -> \"");
1770Sstevel@tonic-gate 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp);
178*4436Sstephh 	out(O_ALTFP|O_VERB3|O_NONL, "\" ");
1790Sstevel@tonic-gate 
180*4436Sstephh 	arrowp = itree_add_arrow(G.arrownp, G.fromnp, G.tonp, infop->ex);
181*4436Sstephh 	if (arrowp == NULL) {
182*4436Sstephh 		out(O_ALTFP|O_VERB3, "(prevented by constraints)");
1830Sstevel@tonic-gate 	} else {
184*4436Sstephh 		out(O_ALTFP|O_VERB3, "");
185*4436Sstephh 		if (!G.frombp) {
186*4436Sstephh 			G.frome = find_or_add_event(infop, G.fromnp);
187*4436Sstephh 			G.frombp = itree_add_bubble(G.frome, B_FROM, G.n, 0);
188*4436Sstephh 		}
189*4436Sstephh 		G.toe = find_or_add_event(infop, G.tonp);
190*4436Sstephh 		G.tobp = itree_add_bubble(G.toe, B_TO, G.k, G.generation);
191*4436Sstephh 		arrowp->tail = G.frombp;
192*4436Sstephh 		arrowp->head = G.tobp;
193*4436Sstephh 		add_arrow(G.frombp, arrowp);
194*4436Sstephh 		add_arrow(G.tobp, arrowp);
1950Sstevel@tonic-gate 	}
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate enum childnode_action {
1990Sstevel@tonic-gate 	CN_NONE,
2000Sstevel@tonic-gate 	CN_DUP
2010Sstevel@tonic-gate };
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate static struct node *
2040Sstevel@tonic-gate tname_dup(struct node *namep, enum childnode_action act)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 	struct node *retp = NULL;
2070Sstevel@tonic-gate 	const char *file;
2080Sstevel@tonic-gate 	int line;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	if (namep == NULL)
2110Sstevel@tonic-gate 		return (NULL);
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	file = namep->file;
2140Sstevel@tonic-gate 	line = namep->line;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	for (; namep != NULL; namep = namep->u.name.next) {
2170Sstevel@tonic-gate 		struct node *newnp = newnode(T_NAME, file, line);
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 		newnp->u.name.t = namep->u.name.t;
2200Sstevel@tonic-gate 		newnp->u.name.s = namep->u.name.s;
2210Sstevel@tonic-gate 		newnp->u.name.last = newnp;
2220Sstevel@tonic-gate 		newnp->u.name.it = namep->u.name.it;
2230Sstevel@tonic-gate 		newnp->u.name.cp = namep->u.name.cp;
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 		if (act == CN_DUP) {
2260Sstevel@tonic-gate 			struct node *npc;
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 			npc = namep->u.name.child;
2290Sstevel@tonic-gate 			if (npc != NULL) {
2300Sstevel@tonic-gate 				switch (npc->t) {
2310Sstevel@tonic-gate 				case T_NUM:
2320Sstevel@tonic-gate 					newnp->u.name.child =
233*4436Sstephh 					    newnode(T_NUM, file, line);
2340Sstevel@tonic-gate 					newnp->u.name.child->u.ull =
235*4436Sstephh 					    npc->u.ull;
2360Sstevel@tonic-gate 					break;
2370Sstevel@tonic-gate 				case T_NAME:
2380Sstevel@tonic-gate 					newnp->u.name.child =
239*4436Sstephh 					    tree_name(npc->u.name.s,
240*4436Sstephh 					    npc->u.name.it, file, line);
2410Sstevel@tonic-gate 					break;
2420Sstevel@tonic-gate 				default:
2430Sstevel@tonic-gate 					out(O_DIE, "tname_dup: "
2440Sstevel@tonic-gate 					    "invalid child type %s",
2450Sstevel@tonic-gate 					    ptree_nodetype2str(npc->t));
2460Sstevel@tonic-gate 				}
2470Sstevel@tonic-gate 			}
2480Sstevel@tonic-gate 		}
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 		if (retp == NULL) {
2510Sstevel@tonic-gate 			retp = newnp;
2520Sstevel@tonic-gate 		} else {
2530Sstevel@tonic-gate 			retp->u.name.last->u.name.next = newnp;
2540Sstevel@tonic-gate 			retp->u.name.last = newnp;
2550Sstevel@tonic-gate 		}
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	return (retp);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate struct prop_wlk_data {
2620Sstevel@tonic-gate 	struct lut *props;
2630Sstevel@tonic-gate 	struct node *epname;
2640Sstevel@tonic-gate };
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate static struct lut *props2instance(struct node *, struct node *);
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate /*
2690Sstevel@tonic-gate  * let oldepname be a subset of epname.  return the subsection of epname
2700Sstevel@tonic-gate  * that ends with oldepname.  make each component in the path explicitly
2710Sstevel@tonic-gate  * instanced (i.e., with a T_NUM child).
2720Sstevel@tonic-gate  */
2730Sstevel@tonic-gate static struct node *
2740Sstevel@tonic-gate tname_dup_to_epname(struct node *oldepname, struct node *epname)
2750Sstevel@tonic-gate {
2760Sstevel@tonic-gate 	struct node *npref, *npend, *np1, *np2;
2770Sstevel@tonic-gate 	struct node *ret = NULL;
2780Sstevel@tonic-gate 	int foundmatch = 0;
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	if (epname == NULL)
2810Sstevel@tonic-gate 		return (NULL);
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	/*
2840Sstevel@tonic-gate 	 * search for the longest path in epname which contains
2850Sstevel@tonic-gate 	 * oldnode->u.event.epname.  set npend to point to just past the
2860Sstevel@tonic-gate 	 * end of this path.
2870Sstevel@tonic-gate 	 */
2880Sstevel@tonic-gate 	npend = NULL;
2890Sstevel@tonic-gate 	for (npref = epname; npref; npref = npref->u.name.next) {
2900Sstevel@tonic-gate 		if (npref->u.name.s == oldepname->u.name.s) {
2910Sstevel@tonic-gate 			for (np1 = npref, np2 = oldepname;
2920Sstevel@tonic-gate 			    np1 != NULL && np2 != NULL;
2930Sstevel@tonic-gate 			    np1 = np1->u.name.next, np2 = np2->u.name.next) {
2940Sstevel@tonic-gate 				if (np1->u.name.s != np2->u.name.s)
2950Sstevel@tonic-gate 					break;
2960Sstevel@tonic-gate 			}
2970Sstevel@tonic-gate 			if (np2 == NULL) {
2980Sstevel@tonic-gate 				foundmatch = 1;
2990Sstevel@tonic-gate 				npend = np1;
3000Sstevel@tonic-gate 				if (np1 == NULL) {
3010Sstevel@tonic-gate 					/* oldepname matched npref up to end */
3020Sstevel@tonic-gate 					break;
3030Sstevel@tonic-gate 				}
3040Sstevel@tonic-gate 			}
3050Sstevel@tonic-gate 		}
3060Sstevel@tonic-gate 	}
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	if (foundmatch == 0) {
3090Sstevel@tonic-gate 		/*
3100Sstevel@tonic-gate 		 * if oldepname could not be found in epname, return a
3110Sstevel@tonic-gate 		 * duplicate of the former.  do not try to instantize
3120Sstevel@tonic-gate 		 * oldepname since it might not be a path.
3130Sstevel@tonic-gate 		 */
3140Sstevel@tonic-gate 		return (tname_dup(oldepname, CN_DUP));
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	/*
3180Sstevel@tonic-gate 	 * dup (epname -- npend).  all children should be T_NUMs.
3190Sstevel@tonic-gate 	 */
3200Sstevel@tonic-gate 	for (npref = epname;
3210Sstevel@tonic-gate 	    ! (npref == NULL || npref == npend);
3220Sstevel@tonic-gate 	    npref = npref->u.name.next) {
3230Sstevel@tonic-gate 		struct node *newnp = newnode(T_NAME, oldepname->file,
324*4436Sstephh 		    oldepname->line);
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		newnp->u.name.t = npref->u.name.t;
3270Sstevel@tonic-gate 		newnp->u.name.s = npref->u.name.s;
3280Sstevel@tonic-gate 		newnp->u.name.last = newnp;
3290Sstevel@tonic-gate 		newnp->u.name.it = npref->u.name.it;
3300Sstevel@tonic-gate 		newnp->u.name.cp = npref->u.name.cp;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 		newnp->u.name.child = newnode(T_NUM, oldepname->file,
333*4436Sstephh 		    oldepname->line);
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 		if (npref->u.name.child == NULL ||
3360Sstevel@tonic-gate 		    npref->u.name.child->t != T_NUM) {
3370Sstevel@tonic-gate 			int childnum;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 			ASSERT(npref->u.name.cp != NULL);
3400Sstevel@tonic-gate 			config_getcompname(npref->u.name.cp, NULL, &childnum);
3410Sstevel@tonic-gate 			newnp->u.name.child->u.ull = childnum;
3420Sstevel@tonic-gate 		} else {
3430Sstevel@tonic-gate 			newnp->u.name.child->u.ull =
344*4436Sstephh 			    npref->u.name.child->u.ull;
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 		if (ret == NULL) {
3480Sstevel@tonic-gate 			ret = newnp;
3490Sstevel@tonic-gate 		} else {
3500Sstevel@tonic-gate 			ret->u.name.last->u.name.next = newnp;
3510Sstevel@tonic-gate 			ret->u.name.last = newnp;
3520Sstevel@tonic-gate 		}
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	return (ret);
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate /*
3590Sstevel@tonic-gate  * restriction: oldnode->u.event.epname has to be equivalent to or a subset
3600Sstevel@tonic-gate  * of epname
3610Sstevel@tonic-gate  */
3620Sstevel@tonic-gate static struct node *
3630Sstevel@tonic-gate tevent_dup_to_epname(struct node *oldnode, struct node *epname)
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate 	struct node *ret;
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	ret = newnode(T_EVENT, oldnode->file, oldnode->line);
3680Sstevel@tonic-gate 	ret->u.event.ename = tname_dup(oldnode->u.event.ename, CN_NONE);
3690Sstevel@tonic-gate 	ret->u.event.epname = tname_dup_to_epname(oldnode->u.event.epname,
370*4436Sstephh 	    epname);
3710Sstevel@tonic-gate 	return (ret);
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate static void
3750Sstevel@tonic-gate nv_instantiate(void *name, void *val, void *arg)
3760Sstevel@tonic-gate {
3770Sstevel@tonic-gate 	struct prop_wlk_data *pd = (struct prop_wlk_data *)arg;
3780Sstevel@tonic-gate 	struct node *orhs = (struct node *)val;
3790Sstevel@tonic-gate 	struct node *nrhs;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	/* handle engines by instantizing the entire engine */
3820Sstevel@tonic-gate 	if (name == L_engine) {
3830Sstevel@tonic-gate 		ASSERT(orhs->t == T_EVENT);
3840Sstevel@tonic-gate 		ASSERT(orhs->u.event.ename->u.name.t == N_SERD);
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 		/* there are only SERD engines for now */
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 		nrhs = newnode(T_SERD, orhs->file, orhs->line);
3890Sstevel@tonic-gate 		nrhs->u.stmt.np = tevent_dup_to_epname(orhs, pd->epname);
3900Sstevel@tonic-gate 		nrhs->u.stmt.lutp = props2instance(orhs, pd->epname);
3910Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
3920Sstevel@tonic-gate 		return;
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	switch (orhs->t) {
3960Sstevel@tonic-gate 	case T_NUM:
3970Sstevel@tonic-gate 		nrhs = newnode(T_NUM, orhs->file, orhs->line);
3980Sstevel@tonic-gate 		nrhs->u.ull = orhs->u.ull;
3990Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4000Sstevel@tonic-gate 		break;
4010Sstevel@tonic-gate 	case T_TIMEVAL:
4020Sstevel@tonic-gate 		nrhs = newnode(T_TIMEVAL, orhs->file, orhs->line);
4030Sstevel@tonic-gate 		nrhs->u.ull = orhs->u.ull;
4040Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4050Sstevel@tonic-gate 		break;
4060Sstevel@tonic-gate 	case T_NAME:
4070Sstevel@tonic-gate 		nrhs = tname_dup_to_epname(orhs, pd->epname);
4080Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4090Sstevel@tonic-gate 		break;
4100Sstevel@tonic-gate 	case T_EVENT:
4110Sstevel@tonic-gate 		nrhs = tevent_dup_to_epname(orhs, pd->epname);
4120Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4130Sstevel@tonic-gate 		break;
4141414Scindi 	case T_GLOBID:
4151414Scindi 		nrhs = newnode(T_GLOBID, orhs->file, orhs->line);
4161414Scindi 		nrhs->u.globid.s = orhs->u.globid.s;
4171414Scindi 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4181414Scindi 		break;
4191414Scindi 	case T_FUNC:
4201414Scindi 		/* for T_FUNC, we don't duplicate it, just point to node */
4211414Scindi 		pd->props = lut_add(pd->props, name, orhs, NULL);
4221414Scindi 		break;
4230Sstevel@tonic-gate 	default:
4241414Scindi 		out(O_DIE, "unexpected nvpair value type %s",
4250Sstevel@tonic-gate 		    ptree_nodetype2str(((struct node *)val)->t));
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate static struct lut *
4300Sstevel@tonic-gate props2instance(struct node *eventnp, struct node *epname)
4310Sstevel@tonic-gate {
4320Sstevel@tonic-gate 	struct prop_wlk_data pd;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	pd.props = NULL;
4350Sstevel@tonic-gate 	pd.epname = epname;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	ASSERT(eventnp->u.event.declp != NULL);
4380Sstevel@tonic-gate 	lut_walk(eventnp->u.event.declp->u.stmt.lutp, nv_instantiate, &pd);
4390Sstevel@tonic-gate 	return (pd.props);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate /*ARGSUSED*/
4430Sstevel@tonic-gate static void
4440Sstevel@tonic-gate instances_destructor(void *left, void *right, void *arg)
4450Sstevel@tonic-gate {
4460Sstevel@tonic-gate 	struct node *dn = (struct node *)right;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	if (dn->t == T_SERD) {
4490Sstevel@tonic-gate 		/* we allocated the lut during itree_create(), so free it */
4500Sstevel@tonic-gate 		lut_free(dn->u.stmt.lutp, instances_destructor, NULL);
4510Sstevel@tonic-gate 		dn->u.stmt.lutp = NULL;
4520Sstevel@tonic-gate 	}
4531414Scindi 	if (dn->t != T_FUNC)	/* T_FUNC pointed to original node */
4541414Scindi 		tree_free(dn);
4551414Scindi }
4561414Scindi 
4571414Scindi /*ARGSUSED*/
4581414Scindi static void
4591414Scindi payloadprops_destructor(void *left, void *right, void *arg)
4601414Scindi {
4611414Scindi 	FREE(right);
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate /*
4650Sstevel@tonic-gate  * event_cmp -- used via lut_lookup/lut_add on instance tree lut
4660Sstevel@tonic-gate  */
4670Sstevel@tonic-gate static int
4680Sstevel@tonic-gate event_cmp(struct event *ep1, struct event *ep2)
4690Sstevel@tonic-gate {
4700Sstevel@tonic-gate 	int diff;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	if ((diff = ep2->enode->u.event.ename->u.name.s -
4730Sstevel@tonic-gate 	    ep1->enode->u.event.ename->u.name.s) != 0)
4740Sstevel@tonic-gate 		return (diff);
4750Sstevel@tonic-gate 	if ((diff = (char *)ep2->ipp - (char *)ep1->ipp) != 0)
4760Sstevel@tonic-gate 		return (diff);
4770Sstevel@tonic-gate 	return (0);
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate struct event *
4820Sstevel@tonic-gate itree_lookup(struct lut *itp, const char *ename, const struct ipath *ipp)
4830Sstevel@tonic-gate {
4840Sstevel@tonic-gate 	struct event searchevent;	/* just used for searching */
4850Sstevel@tonic-gate 	struct node searcheventnode;
4860Sstevel@tonic-gate 	struct node searchenamenode;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	searchevent.enode = &searcheventnode;
4890Sstevel@tonic-gate 	searcheventnode.t = T_EVENT;
4900Sstevel@tonic-gate 	searcheventnode.u.event.ename = &searchenamenode;
4910Sstevel@tonic-gate 	searchenamenode.t = T_NAME;
4920Sstevel@tonic-gate 	searchenamenode.u.name.s = ename;
4930Sstevel@tonic-gate 	searchevent.ipp = ipp;
4940Sstevel@tonic-gate 	return (lut_lookup(itp, (void *)&searchevent, (lut_cmp)event_cmp));
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate static struct event *
4980Sstevel@tonic-gate find_or_add_event(struct info *infop, struct node *np)
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	struct event *ret;
5010Sstevel@tonic-gate 	struct event searchevent;	/* just used for searching */
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	ASSERTeq(np->t, T_EVENT, ptree_nodetype2str);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	searchevent.enode = np;
5060Sstevel@tonic-gate 	searchevent.ipp = ipath(np->u.event.epname);
5070Sstevel@tonic-gate 	if ((ret = lut_lookup(infop->lut, (void *)&searchevent,
5080Sstevel@tonic-gate 	    (lut_cmp)event_cmp)) != NULL)
5090Sstevel@tonic-gate 		return (ret);
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	/* wasn't already in tree, allocate it */
512*4436Sstephh 	ret = alloc_xmalloc(sizeof (*ret));
5130Sstevel@tonic-gate 	bzero(ret, sizeof (*ret));
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	ret->t = np->u.event.ename->u.name.t;
5160Sstevel@tonic-gate 	ret->enode = np;
5170Sstevel@tonic-gate 	ret->ipp = searchevent.ipp;
5180Sstevel@tonic-gate 	ret->props = props2instance(np, np->u.event.epname);
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	infop->lut = lut_add(infop->lut, (void *)ret, (void *)ret,
5210Sstevel@tonic-gate 	    (lut_cmp)event_cmp);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	return (ret);
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate /*
5270Sstevel@tonic-gate  * hmatch_event -- perform any appropriate horizontal expansion on an event
5280Sstevel@tonic-gate  *
5290Sstevel@tonic-gate  * this routine is used to perform horizontal expansion on both the
5300Sstevel@tonic-gate  * left-hand-side events in a prop, and the right-hand-side events.
5310Sstevel@tonic-gate  * when called to handle a left-side event, nextnp point to the right
5320Sstevel@tonic-gate  * side of the prop that should be passed to hmatch() for each match
5330Sstevel@tonic-gate  * found by horizontal expansion.   when no horizontal expansion exists,
5340Sstevel@tonic-gate  * we will still "match" one event for every event found in the list on
5350Sstevel@tonic-gate  * the left-hand-side of the prop because vmatch() already found that
5360Sstevel@tonic-gate  * there's at least one match during vertical expansion.
5370Sstevel@tonic-gate  */
5380Sstevel@tonic-gate static void
5390Sstevel@tonic-gate hmatch_event(struct info *infop, struct node *eventnp, struct node *epname,
5400Sstevel@tonic-gate     struct config *ncp, struct node *nextnp, int rematch)
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate 	if (epname == NULL) {
5430Sstevel@tonic-gate 		/*
5440Sstevel@tonic-gate 		 * end of pathname recursion, either we just located
5450Sstevel@tonic-gate 		 * a left-hand-side event and we're ready to move on
5460Sstevel@tonic-gate 		 * to the expanding the right-hand-side events, or
5470Sstevel@tonic-gate 		 * we're further down the recursion and we just located
5480Sstevel@tonic-gate 		 * a right-hand-side event.  the passed-in parameter
5490Sstevel@tonic-gate 		 * "nextnp" tells us whether we're working on the left
5500Sstevel@tonic-gate 		 * side and need to move on to nextnp, or if nextnp is
5510Sstevel@tonic-gate 		 * NULL, we're working on the right side.
5520Sstevel@tonic-gate 		 */
5530Sstevel@tonic-gate 		if (nextnp) {
5540Sstevel@tonic-gate 			/*
5550Sstevel@tonic-gate 			 * finished a left side expansion, move on to right.
5560Sstevel@tonic-gate 			 * tell generate() what event we just matched so
5570Sstevel@tonic-gate 			 * it can be used at the source of any arrows
5580Sstevel@tonic-gate 			 * we generate as we match events on the right side.
5590Sstevel@tonic-gate 			 */
560*4436Sstephh 			generate_from(eventnp);
5610Sstevel@tonic-gate 			hmatch(infop, nextnp, NULL);
5620Sstevel@tonic-gate 		} else {
5630Sstevel@tonic-gate 			/*
5640Sstevel@tonic-gate 			 * finished a right side expansion.  tell generate
5650Sstevel@tonic-gate 			 * the information about the destination and let
5660Sstevel@tonic-gate 			 * it construct the arrows as appropriate.
5670Sstevel@tonic-gate 			 */
568*4436Sstephh 			generate_to(eventnp);
569*4436Sstephh 			generate(infop);
5700Sstevel@tonic-gate 		}
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 		return;
5730Sstevel@tonic-gate 	}
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	ASSERTeq(epname->t, T_NAME, ptree_nodetype2str);
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	/*
5780Sstevel@tonic-gate 	 * we only get here when eventnp already has a completely
5790Sstevel@tonic-gate 	 * instanced epname in it already.  so we first recurse
5800Sstevel@tonic-gate 	 * down to the end of the name and as the recursion pops
5810Sstevel@tonic-gate 	 * up, we look for opportunities to advance horizontal
582*4436Sstephh 	 * expansions on to the next match.
5830Sstevel@tonic-gate 	 */
584*4436Sstephh 	if (epname->u.name.it == IT_HORIZONTAL || rematch) {
5850Sstevel@tonic-gate 		struct config *cp;
5860Sstevel@tonic-gate 		struct config *ocp = epname->u.name.cp;
5870Sstevel@tonic-gate 		char *cp_s;
5880Sstevel@tonic-gate 		int cp_num;
5890Sstevel@tonic-gate 		int ocp_num;
5900Sstevel@tonic-gate 		struct iterinfo *iterinfop = NULL;
5910Sstevel@tonic-gate 		const char *iters;
592*4436Sstephh 		int hexpand = 0;
5930Sstevel@tonic-gate 
594*4436Sstephh 		if (epname->u.name.it != IT_HORIZONTAL) {
595*4436Sstephh 			/*
596*4436Sstephh 			 * Ancestor was horizontal though, so must rematch
597*4436Sstephh 			 * against the name/num found in vmatch.
598*4436Sstephh 			 */
599*4436Sstephh 			config_getcompname(ocp, NULL, &ocp_num);
600*4436Sstephh 		} else {
601*4436Sstephh 			iters = epname->u.name.child->u.name.s;
602*4436Sstephh 			if ((iterinfop = lut_lookup(infop->ex,
603*4436Sstephh 			    (void *)iters, NULL)) == NULL) {
604*4436Sstephh 				/*
605*4436Sstephh 				 * do horizontal expansion on this node
606*4436Sstephh 				 */
607*4436Sstephh 				hexpand = 1;
608*4436Sstephh 				iterinfop = alloc_xmalloc(
609*4436Sstephh 				    sizeof (struct iterinfo));
610*4436Sstephh 				iterinfop->num = -1;
611*4436Sstephh 				iterinfop->np = epname;
612*4436Sstephh 				infop->ex = lut_add(infop->ex, (void *)iters,
613*4436Sstephh 				    iterinfop, NULL);
614*4436Sstephh 			} else if (iterinfop->num == -1) {
615*4436Sstephh 				hexpand = 1;
616*4436Sstephh 			} else {
617*4436Sstephh 				/*
618*4436Sstephh 				 * This name has already been used in a
619*4436Sstephh 				 * horizontal expansion. This time just match it
620*4436Sstephh 				 */
621*4436Sstephh 				ocp_num = iterinfop->num;
622*4436Sstephh 			}
623*4436Sstephh 		}
624*4436Sstephh 		/*
625*4436Sstephh 		 * Run through siblings looking for any that match the name.
626*4436Sstephh 		 * If hexpand not set then num must also match ocp_num.
627*4436Sstephh 		 */
628*4436Sstephh 		for (cp = rematch ? ncp : ocp; cp; cp = config_next(cp)) {
629*4436Sstephh 			config_getcompname(cp, &cp_s, &cp_num);
630*4436Sstephh 			if (cp_s == epname->u.name.s) {
631*4436Sstephh 				if (hexpand)
6320Sstevel@tonic-gate 					iterinfop->num = cp_num;
633*4436Sstephh 				else if (ocp_num != cp_num)
634*4436Sstephh 					continue;
6350Sstevel@tonic-gate 				epname->u.name.cp = cp;
6360Sstevel@tonic-gate 				hmatch_event(infop, eventnp,
6370Sstevel@tonic-gate 				    epname->u.name.next, config_child(cp),
6380Sstevel@tonic-gate 				    nextnp, 1);
6390Sstevel@tonic-gate 			}
6400Sstevel@tonic-gate 		}
6410Sstevel@tonic-gate 		epname->u.name.cp = ocp;
642*4436Sstephh 		if (hexpand)
643*4436Sstephh 			iterinfop->num = -1;
644*4436Sstephh 	} else {
645*4436Sstephh 		hmatch_event(infop, eventnp, epname->u.name.next,
646*4436Sstephh 		    NULL, nextnp, 0);
6470Sstevel@tonic-gate 	}
6480Sstevel@tonic-gate }
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate /*
6510Sstevel@tonic-gate  * hmatch -- check for horizontal expansion matches
6520Sstevel@tonic-gate  *
6530Sstevel@tonic-gate  * np points to the things we're matching (like a T_LIST or a T_EVENT)
6540Sstevel@tonic-gate  * and if we're working on a left-side of a prop, nextnp points to
6550Sstevel@tonic-gate  * the other side of the prop that we'll tackle next when this recursion
6560Sstevel@tonic-gate  * bottoms out.  when all the events in the entire prop arrow have been
6570Sstevel@tonic-gate  * horizontally expanded, generate() will be called to generate the
6580Sstevel@tonic-gate  * actualy arrow.
6590Sstevel@tonic-gate  */
6600Sstevel@tonic-gate static void
6610Sstevel@tonic-gate hmatch(struct info *infop, struct node *np, struct node *nextnp)
6620Sstevel@tonic-gate {
6630Sstevel@tonic-gate 	if (np == NULL)
6640Sstevel@tonic-gate 		return;		/* all done */
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	/*
6670Sstevel@tonic-gate 	 * for each item in the list of events (which could just
6680Sstevel@tonic-gate 	 * be a single event, or it could get larger in the loop
6690Sstevel@tonic-gate 	 * below due to horizontal expansion), call hmatch on
6700Sstevel@tonic-gate 	 * the right side and create arrows to each element.
6710Sstevel@tonic-gate 	 */
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	switch (np->t) {
6740Sstevel@tonic-gate 	case T_LIST:
6750Sstevel@tonic-gate 		/* loop through the list */
6760Sstevel@tonic-gate 		if (np->u.expr.left)
6770Sstevel@tonic-gate 			hmatch(infop, np->u.expr.left, nextnp);
6780Sstevel@tonic-gate 		if (np->u.expr.right)
6790Sstevel@tonic-gate 			hmatch(infop, np->u.expr.right, nextnp);
6800Sstevel@tonic-gate 		break;
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	case T_EVENT:
6830Sstevel@tonic-gate 		hmatch_event(infop, np, np->u.event.epname,
6840Sstevel@tonic-gate 		    NULL, nextnp, 0);
6850Sstevel@tonic-gate 		break;
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	default:
6880Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
6890Sstevel@tonic-gate 		    "hmatch: unexpected type: %s",
6900Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
6910Sstevel@tonic-gate 	}
6920Sstevel@tonic-gate }
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate static int
6950Sstevel@tonic-gate itree_np2nork(struct node *norknp)
6960Sstevel@tonic-gate {
6970Sstevel@tonic-gate 	if (norknp == NULL)
6980Sstevel@tonic-gate 		return (1);
6990Sstevel@tonic-gate 	else if (norknp->t == T_NAME && norknp->u.name.s == L_A)
7000Sstevel@tonic-gate 		return (-1);	/* our internal version of "all" */
7010Sstevel@tonic-gate 	else if (norknp->t == T_NUM)
7020Sstevel@tonic-gate 		return ((int)norknp->u.ull);
7030Sstevel@tonic-gate 	else
704*4436Sstephh 		outfl(O_DIE, norknp->file, norknp->line,
7050Sstevel@tonic-gate 		    "itree_np2nork: internal error type %s",
7060Sstevel@tonic-gate 		    ptree_nodetype2str(norknp->t));
7070Sstevel@tonic-gate 	/*NOTREACHED*/
7081717Swesolows 	return (1);
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate static struct iterinfo *
7120Sstevel@tonic-gate newiterinfo(int num, struct node *np)
7130Sstevel@tonic-gate {
714*4436Sstephh 	struct iterinfo *ret = alloc_xmalloc(sizeof (*ret));
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	ret->num = num;
7170Sstevel@tonic-gate 	ret->np = np;
7180Sstevel@tonic-gate 	return (ret);
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate /*ARGSUSED*/
7220Sstevel@tonic-gate static void
7230Sstevel@tonic-gate iterinfo_destructor(void *left, void *right, void *arg)
7240Sstevel@tonic-gate {
7250Sstevel@tonic-gate 	struct iterinfo *iterinfop = (struct iterinfo *)right;
7260Sstevel@tonic-gate 
727*4436Sstephh 	alloc_xfree(iterinfop, sizeof (*iterinfop));
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate 
730*4436Sstephh static void
731*4436Sstephh vmatch_event(struct info *infop, struct config *cp, struct node *np,
732*4436Sstephh 	    struct node *lnp, struct node *anp, struct wildcardinfo *wcp)
733186Sdb35262 {
734*4436Sstephh 	char *cp_s;
735*4436Sstephh 	int cp_num;
736*4436Sstephh 	struct node *ewlp, *ewfp;
737*4436Sstephh 	struct config *pcp;
738*4436Sstephh 	struct node *cpnode;
739*4436Sstephh 	int newewname = 0;
740186Sdb35262 
741*4436Sstephh 	if (np == NULL) {
742186Sdb35262 		/*
743*4436Sstephh 		 * Reached the end of the name. u.name.cp pointers should be set
744*4436Sstephh 		 * up for each part of name. From this we can use config tree
745*4436Sstephh 		 * to build up the wildcard part of the name (if any).
746186Sdb35262 		 */
747*4436Sstephh 		pcp = config_parent(wcp->nptop->u.event.epname->u.name.cp);
748*4436Sstephh 		if (pcp == infop->croot) {
749*4436Sstephh 			/*
750*4436Sstephh 			 * no wildcarding done - move on to next entry
751*4436Sstephh 			 */
752*4436Sstephh 			wcp->nptop->u.event.ewname = wcp->ewname;
753*4436Sstephh 			wcp->nptop->u.event.oldepname = wcp->oldepname;
754*4436Sstephh 			vmatch(infop, np, lnp, anp);
755*4436Sstephh 			return;
756*4436Sstephh 		}
757*4436Sstephh 		if (wcp->ewname == NULL) {
758*4436Sstephh 			/*
759*4436Sstephh 			 * ewname not yet set up - do it now
760*4436Sstephh 			 */
761*4436Sstephh 			newewname = 1;
762*4436Sstephh 			for (; pcp != infop->croot; pcp = config_parent(pcp)) {
763*4436Sstephh 				config_getcompname(pcp, &cp_s, &cp_num);
764*4436Sstephh 				cpnode = tree_name(cp_s, IT_NONE, NULL, 0);
765*4436Sstephh 				cpnode->u.name.child = newnode(T_NUM, NULL, 0);
766*4436Sstephh 				cpnode->u.name.child->u.ull = cp_num;
767*4436Sstephh 				cpnode->u.name.cp = pcp;
768*4436Sstephh 				if (wcp->ewname != NULL) {
769*4436Sstephh 					cpnode->u.name.next = wcp->ewname;
770*4436Sstephh 					cpnode->u.name.last =
771*4436Sstephh 					    wcp->ewname->u.name.last;
772*4436Sstephh 				}
773*4436Sstephh 				wcp->ewname = cpnode;
774*4436Sstephh 			}
775*4436Sstephh 		}
776186Sdb35262 
777186Sdb35262 		/*
778*4436Sstephh 		 * dup ewname and append oldepname
779186Sdb35262 		 */
780*4436Sstephh 		ewfp = tname_dup(wcp->ewname, CN_DUP);
781*4436Sstephh 		ewlp = ewfp->u.name.last;
782*4436Sstephh 		ewfp->u.name.last = wcp->oldepname->u.name.last;
783*4436Sstephh 		ewlp->u.name.next = wcp->oldepname;
784*4436Sstephh 
785*4436Sstephh 		wcp->nptop->u.event.epname = ewfp;
786*4436Sstephh 		wcp->nptop->u.event.ewname = wcp->ewname;
787*4436Sstephh 		wcp->nptop->u.event.oldepname = wcp->oldepname;
788*4436Sstephh 		vmatch(infop, np, lnp, anp);
789*4436Sstephh 		wcp->nptop->u.event.epname = wcp->oldepname;
790186Sdb35262 
791*4436Sstephh 		/*
792*4436Sstephh 		 * reduce duped ewname to original then free
793*4436Sstephh 		 */
794*4436Sstephh 		ewlp->u.name.next = NULL;
795*4436Sstephh 		ewfp->u.name.last = ewlp;
796*4436Sstephh 		tree_free(ewfp);
797186Sdb35262 
798*4436Sstephh 		if (newewname) {
799*4436Sstephh 			/*
800*4436Sstephh 			 * free ewname if allocated above
801*4436Sstephh 			 */
802*4436Sstephh 			tree_free(wcp->ewname);
803*4436Sstephh 			wcp->ewname = NULL;
804*4436Sstephh 		}
805*4436Sstephh 		return;
806186Sdb35262 	}
807186Sdb35262 
808186Sdb35262 	/*
809*4436Sstephh 	 * We have an np. See if we can match it in this section of
810*4436Sstephh 	 * the config tree.
8110Sstevel@tonic-gate 	 */
8120Sstevel@tonic-gate 	if (cp == NULL)
8130Sstevel@tonic-gate 		return;	/* no more config to match against */
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	for (; cp; cp = config_next(cp)) {
8160Sstevel@tonic-gate 		config_getcompname(cp, &cp_s, &cp_num);
8170Sstevel@tonic-gate 
818*4436Sstephh 		if (cp_s == np->u.name.s) {
8190Sstevel@tonic-gate 			/* found a matching component name */
8200Sstevel@tonic-gate 			if (np->u.name.child &&
8210Sstevel@tonic-gate 			    np->u.name.child->t == T_NUM) {
8220Sstevel@tonic-gate 				/*
8230Sstevel@tonic-gate 				 * an explicit instance number was given
8240Sstevel@tonic-gate 				 * in the source.  so only consider this
8250Sstevel@tonic-gate 				 * a configuration match if the number
8260Sstevel@tonic-gate 				 * also matches.
8270Sstevel@tonic-gate 				 */
8280Sstevel@tonic-gate 				if (cp_num != np->u.name.child->u.ull)
8290Sstevel@tonic-gate 					continue;
8300Sstevel@tonic-gate 
831*4436Sstephh 			} else if (np->u.name.it != IT_HORIZONTAL) {
8320Sstevel@tonic-gate 				struct iterinfo *iterinfop;
8330Sstevel@tonic-gate 				const char *iters;
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 				/*
8360Sstevel@tonic-gate 				 * vertical iterator.  look it up in
8370Sstevel@tonic-gate 				 * the appropriate lut and if we get
8380Sstevel@tonic-gate 				 * back a value it is either one that we
8390Sstevel@tonic-gate 				 * set earlier, in which case we record
8400Sstevel@tonic-gate 				 * the new value for this iteration and
8410Sstevel@tonic-gate 				 * keep matching, or it is one that was
8420Sstevel@tonic-gate 				 * set by an earlier reference to the
8430Sstevel@tonic-gate 				 * iterator, in which case we only consider
8440Sstevel@tonic-gate 				 * this a configuration match if the number
8450Sstevel@tonic-gate 				 * matches cp_num.
8460Sstevel@tonic-gate 				 */
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 				ASSERT(np->u.name.child != NULL);
8490Sstevel@tonic-gate 				ASSERT(np->u.name.child->t == T_NAME);
8500Sstevel@tonic-gate 				iters = np->u.name.child->u.name.s;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 				if ((iterinfop = lut_lookup(infop->ex,
8530Sstevel@tonic-gate 				    (void *)iters, NULL)) == NULL) {
8540Sstevel@tonic-gate 					/* we're the first use, record our np */
8550Sstevel@tonic-gate 					infop->ex = lut_add(infop->ex,
8560Sstevel@tonic-gate 					    (void *)iters,
8570Sstevel@tonic-gate 					    newiterinfo(cp_num, np), NULL);
8580Sstevel@tonic-gate 				} else if (np == iterinfop->np) {
8590Sstevel@tonic-gate 					/*
8600Sstevel@tonic-gate 					 * we're the first use, back again
8610Sstevel@tonic-gate 					 * for another iteration.  so update
8620Sstevel@tonic-gate 					 * the num bound to this iterator in
8630Sstevel@tonic-gate 					 * the lut.
8640Sstevel@tonic-gate 					 */
8650Sstevel@tonic-gate 					iterinfop->num = cp_num;
8660Sstevel@tonic-gate 				} else if (cp_num != iterinfop->num) {
8670Sstevel@tonic-gate 					/*
8680Sstevel@tonic-gate 					 * an earlier reference to this
8690Sstevel@tonic-gate 					 * iterator bound it to a different
8700Sstevel@tonic-gate 					 * instance number, so there's no
8710Sstevel@tonic-gate 					 * match here after all.
872186Sdb35262 					 *
873186Sdb35262 					 * however, it's possible that this
874186Sdb35262 					 * component should really be part of
875186Sdb35262 					 * the wildcard.  we explore this by
876186Sdb35262 					 * forcing this component into the
877186Sdb35262 					 * wildcarded section.
878186Sdb35262 					 *
879186Sdb35262 					 * for an more details of what's
880186Sdb35262 					 * going to happen now, see
881186Sdb35262 					 * comments block below entitled
882186Sdb35262 					 * "forcing components into
883186Sdb35262 					 * wildcard path".
8840Sstevel@tonic-gate 					 */
885*4436Sstephh 					if (np == wcp->nptop->u.event.epname)
886*4436Sstephh 						vmatch_event(infop,
887*4436Sstephh 						    config_child(cp), np, lnp,
888*4436Sstephh 						    anp, wcp);
8890Sstevel@tonic-gate 					continue;
8900Sstevel@tonic-gate 				}
8910Sstevel@tonic-gate 			}
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 			/*
894*4436Sstephh 			 * if this was an IT_HORIZONTAL name, hmatch() will
895*4436Sstephh 			 * expand all matches horizontally into a list.
8960Sstevel@tonic-gate 			 * we know the list will contain at least
8970Sstevel@tonic-gate 			 * one element (the one we just matched),
898*4436Sstephh 			 * so we just let hmatch_event() do the rest.
8990Sstevel@tonic-gate 			 *
900*4436Sstephh 			 * recurse on to next component. Note that
9010Sstevel@tonic-gate 			 * wildcarding is now turned off.
9020Sstevel@tonic-gate 			 */
903*4436Sstephh 			np->u.name.cp = cp;
9040Sstevel@tonic-gate 			vmatch_event(infop, config_child(cp), np->u.name.next,
905*4436Sstephh 			    lnp, anp, wcp);
906*4436Sstephh 			np->u.name.cp = NULL;
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 			/*
909186Sdb35262 			 * forcing components into wildcard path:
910186Sdb35262 			 *
911186Sdb35262 			 * if this component is the first match, force it
912186Sdb35262 			 * to be part of the wildcarded path and see if we
913*4436Sstephh 			 * can get additional matches.
914186Sdb35262 			 *
915186Sdb35262 			 * here's an example.  suppose we have the
916186Sdb35262 			 * definition
917186Sdb35262 			 *	event foo@x/y
918186Sdb35262 			 * and configuration
919186Sdb35262 			 *	a0/x0/y0/a1/x1/y1
920186Sdb35262 			 *
921186Sdb35262 			 * the code up to this point will treat "a0" as the
922186Sdb35262 			 * wildcarded part of the path and "x0/y0" as the
923186Sdb35262 			 * nonwildcarded part, resulting in the instanced
924186Sdb35262 			 * event
925186Sdb35262 			 *	foo@a0/x0/y0
926186Sdb35262 			 *
927186Sdb35262 			 * in order to discover the next match (.../x1/y1)
928186Sdb35262 			 * in the configuration we have to force "x0" into
929*4436Sstephh 			 * the wildcarded part of the path.
930186Sdb35262 			 * by doing so, we discover the wildcarded part
931186Sdb35262 			 * "a0/x0/y0/a1" and the nonwildcarded part "x1/y1"
932186Sdb35262 			 *
933186Sdb35262 			 * the following call to vmatch_event() is also
934186Sdb35262 			 * needed to properly handle the configuration
935186Sdb35262 			 *	b0/x0/b1/x1/y1
936186Sdb35262 			 *
937186Sdb35262 			 * the recursions into vmatch_event() will start
938186Sdb35262 			 * off uncovering "b0" as the wildcarded part and
939186Sdb35262 			 * "x0" as the start of the nonwildcarded path.
940186Sdb35262 			 * however, the next recursion will not result in a
941186Sdb35262 			 * match since there is no "y" following "x0".  the
942186Sdb35262 			 * subsequent match of (wildcard = "b0/x0/b1" and
943186Sdb35262 			 * nonwildcard = "x1/y1") will be discovered only
944186Sdb35262 			 * if "x0" is forced to be a part of the wildcarded
945186Sdb35262 			 * path.
9460Sstevel@tonic-gate 			 */
947*4436Sstephh 			if (np == wcp->nptop->u.event.epname)
948*4436Sstephh 				vmatch_event(infop, config_child(cp), np, lnp,
949*4436Sstephh 				    anp, wcp);
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 			if (np->u.name.it == IT_HORIZONTAL) {
9520Sstevel@tonic-gate 				/*
9530Sstevel@tonic-gate 				 * hmatch() finished iterating through
9540Sstevel@tonic-gate 				 * the configuration as described above, so
9550Sstevel@tonic-gate 				 * don't continue iterating here.
9560Sstevel@tonic-gate 				 */
9570Sstevel@tonic-gate 				return;
9580Sstevel@tonic-gate 			}
959*4436Sstephh 		} else if (np == wcp->nptop->u.event.epname) {
9600Sstevel@tonic-gate 			/*
961*4436Sstephh 			 * no match - carry on down the tree looking for
962*4436Sstephh 			 * wildcarding
9630Sstevel@tonic-gate 			 */
9640Sstevel@tonic-gate 			vmatch_event(infop, config_child(cp), np, lnp, anp,
965*4436Sstephh 			    wcp);
9660Sstevel@tonic-gate 		}
9670Sstevel@tonic-gate 	}
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate /*
9710Sstevel@tonic-gate  * vmatch -- find the next vertical expansion match in the config database
9720Sstevel@tonic-gate  *
9730Sstevel@tonic-gate  * this routine is called with three node pointers:
9740Sstevel@tonic-gate  *	 np -- the parse we're matching
9750Sstevel@tonic-gate  *	lnp -- the rest of the list we're currently working on
9760Sstevel@tonic-gate  *	anp -- the rest of the arrow we're currently working on
9770Sstevel@tonic-gate  *
9780Sstevel@tonic-gate  * the expansion matching happens via three types of recursion:
9790Sstevel@tonic-gate  *
9800Sstevel@tonic-gate  *	- when given an arrow, handle the left-side and then recursively
9810Sstevel@tonic-gate  *	  handle the right side (which might be another cascaded arrow).
9820Sstevel@tonic-gate  *
9830Sstevel@tonic-gate  *	- when handling one side of an arrow, recurse through the T_LIST
9840Sstevel@tonic-gate  *	  to get to each event (or just move on to the event if there
9850Sstevel@tonic-gate  *	  is a single event instead of a list)  since the arrow parse
9860Sstevel@tonic-gate  *	  trees recurse left, we actually start with the right-most
9870Sstevel@tonic-gate  *	  event list in the prop statement and work our way towards
9880Sstevel@tonic-gate  *	  the left-most event list.
9890Sstevel@tonic-gate  *
9900Sstevel@tonic-gate  *	- when handling an event, recurse down each component of the
9910Sstevel@tonic-gate  *	  pathname, matching in the config database and recording the
9920Sstevel@tonic-gate  *	  matches in the explicit iterator dictionary as we go.
9930Sstevel@tonic-gate  *
9940Sstevel@tonic-gate  * when the bottom of this matching recursion is met, meaning we have
9950Sstevel@tonic-gate  * set the "cp" pointers on all the names in the entire statement,
9960Sstevel@tonic-gate  * we call hmatch() which does it's own recursion to handle horizontal
9970Sstevel@tonic-gate  * expandsion and then call generate() to generate nodes, bubbles, and
9980Sstevel@tonic-gate  * arrows in the instance tree.  generate() looks at the cp pointers to
9990Sstevel@tonic-gate  * see what instance numbers were matched in the configuration database.
10000Sstevel@tonic-gate  *
10010Sstevel@tonic-gate  * when horizontal expansion appears, vmatch() finds only the first match
10020Sstevel@tonic-gate  * and hmatch() then takes the horizontal expansion through all the other
10030Sstevel@tonic-gate  * matches when generating the arrows in the instance tree.
10040Sstevel@tonic-gate  *
10050Sstevel@tonic-gate  * the "infop" passed down through the recursion contains a dictionary
10060Sstevel@tonic-gate  * of the explicit iterators (all the implicit iterators have been converted
10070Sstevel@tonic-gate  * to explicit iterators when the parse tree was created by tree.c), which
10080Sstevel@tonic-gate  * allows things like this to work correctly:
10090Sstevel@tonic-gate  *
10100Sstevel@tonic-gate  *	prop error.a@x[n]/y/z -> error.b@x/y[n]/z -> error.c@x/y/z[n];
10110Sstevel@tonic-gate  *
10120Sstevel@tonic-gate  * during the top level call, the explicit iterator "n" will match an
10130Sstevel@tonic-gate  * instance number in the config database, and the result will be recorded
10140Sstevel@tonic-gate  * in the explicit iterator dictionary and passed down via "infop".  so
10150Sstevel@tonic-gate  * when the recursive call tries to match y[n] in the config database, it
10160Sstevel@tonic-gate  * will only match the same instance number as x[n] did since the dictionary
10170Sstevel@tonic-gate  * is consulted to see if "n" took on a value already.
10180Sstevel@tonic-gate  *
10190Sstevel@tonic-gate  * at any point during the recursion, match*() can return to indicate
10200Sstevel@tonic-gate  * a match was not found in the config database and that the caller should
10210Sstevel@tonic-gate  * move on to the next potential match, if any.
10220Sstevel@tonic-gate  *
10230Sstevel@tonic-gate  * constraints are completely ignored by match(), so the statement:
10240Sstevel@tonic-gate  *
10250Sstevel@tonic-gate  *	prop error.a@x[n] -> error.b@x[n] {n != 0};
10260Sstevel@tonic-gate  *
10270Sstevel@tonic-gate  * might very well match x[0] if it appears in the config database.  it
10280Sstevel@tonic-gate  * is the generate() routine that takes that match and then decides what
10290Sstevel@tonic-gate  * arrow, if any, should be generated in the instance tree.  generate()
10300Sstevel@tonic-gate  * looks at the explicit iterator dictionary to get values like "n" in
10310Sstevel@tonic-gate  * the above example so that it can evaluate constraints.
10320Sstevel@tonic-gate  *
10330Sstevel@tonic-gate  */
10340Sstevel@tonic-gate static void
1035*4436Sstephh vmatch(struct info *infop, struct node *np, struct node *lnp, struct node *anp)
10360Sstevel@tonic-gate {
1037*4436Sstephh 	struct node *np1, *np2, *oldepname, *oldnptop;
1038*4436Sstephh 	int epmatches;
1039*4436Sstephh 	struct config *cp;
1040*4436Sstephh 	struct wildcardinfo *wcp;
1041*4436Sstephh 
10420Sstevel@tonic-gate 	if (np == NULL) {
10430Sstevel@tonic-gate 		if (lnp)
1044*4436Sstephh 			vmatch(infop, lnp, NULL, anp);
10450Sstevel@tonic-gate 		else if (anp)
1046*4436Sstephh 			vmatch(infop, anp, NULL, NULL);
10470Sstevel@tonic-gate 		else {
10480Sstevel@tonic-gate 			struct node *src;
10490Sstevel@tonic-gate 			struct node *dst;
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 			/* end of vertical match recursion */
10520Sstevel@tonic-gate 			outfl(O_ALTFP|O_VERB3|O_NONL,
10530Sstevel@tonic-gate 			    infop->anp->file, infop->anp->line, "vmatch: ");
10540Sstevel@tonic-gate 			ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, infop->anp);
10550Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3, NULL);
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 			generate_nork(
10580Sstevel@tonic-gate 			    itree_np2nork(infop->anp->u.arrow.nnp),
10590Sstevel@tonic-gate 			    itree_np2nork(infop->anp->u.arrow.knp));
10600Sstevel@tonic-gate 			dst = infop->anp->u.arrow.rhs;
10610Sstevel@tonic-gate 			src = infop->anp->u.arrow.lhs;
10620Sstevel@tonic-gate 			for (;;) {
10630Sstevel@tonic-gate 				generate_new();	/* new set of arrows */
10640Sstevel@tonic-gate 				if (src->t == T_ARROW) {
10650Sstevel@tonic-gate 					hmatch(infop, src->u.arrow.rhs, dst);
10660Sstevel@tonic-gate 					generate_nork(
10670Sstevel@tonic-gate 					    itree_np2nork(src->u.arrow.nnp),
10680Sstevel@tonic-gate 					    itree_np2nork(src->u.arrow.knp));
10690Sstevel@tonic-gate 					dst = src->u.arrow.rhs;
10700Sstevel@tonic-gate 					src = src->u.arrow.lhs;
10710Sstevel@tonic-gate 				} else {
10720Sstevel@tonic-gate 					hmatch(infop, src, dst);
10730Sstevel@tonic-gate 					break;
10740Sstevel@tonic-gate 				}
10750Sstevel@tonic-gate 			}
10760Sstevel@tonic-gate 		}
10770Sstevel@tonic-gate 		return;
10780Sstevel@tonic-gate 	}
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	switch (np->t) {
10810Sstevel@tonic-gate 	case T_EVENT: {
1082*4436Sstephh 		epmatches = 0;
1083*4436Sstephh 		/*
1084*4436Sstephh 		 * see if we already have a match in the wcps
1085*4436Sstephh 		 */
1086*4436Sstephh 		for (wcp = wcproot; wcp; wcp = wcp->next) {
1087*4436Sstephh 			oldepname = wcp->oldepname;
1088*4436Sstephh 			oldnptop = wcp->nptop;
1089*4436Sstephh 			for (np1 = oldepname, np2 = np->u.event.epname;
1090*4436Sstephh 			    np1 != NULL && np2 != NULL; np1 = np1->u.name.next,
1091*4436Sstephh 			    np2 = np2->u.name.next) {
1092*4436Sstephh 				if (strcmp(np1->u.name.s, np2->u.name.s) != 0)
1093*4436Sstephh 					break;
1094*4436Sstephh 				if (np1->u.name.child->t !=
1095*4436Sstephh 				    np2->u.name.child->t)
1096*4436Sstephh 					break;
1097*4436Sstephh 				if (np1->u.name.child->t == T_NUM &&
1098*4436Sstephh 				    np1->u.name.child->u.ull !=
1099*4436Sstephh 				    np2->u.name.child->u.ull)
1100*4436Sstephh 					break;
1101*4436Sstephh 				if (np1->u.name.child->t == T_NAME &&
1102*4436Sstephh 				    strcmp(np1->u.name.child->u.name.s,
1103*4436Sstephh 				    np2->u.name.child->u.name.s) != 0)
1104*4436Sstephh 					break;
1105*4436Sstephh 				epmatches++;
1106*4436Sstephh 			}
1107*4436Sstephh 			if (epmatches)
1108*4436Sstephh 				break;
1109*4436Sstephh 		}
1110*4436Sstephh 		if (epmatches && np1 == NULL && np2 == NULL) {
1111*4436Sstephh 			/*
1112*4436Sstephh 			 * complete names match, can just borrow the fields
1113*4436Sstephh 			 */
1114*4436Sstephh 			oldepname = np->u.event.epname;
1115*4436Sstephh 			np->u.event.epname = oldnptop->u.event.epname;
1116*4436Sstephh 			np->u.event.oldepname = wcp->oldepname;
1117*4436Sstephh 			np->u.event.ewname = wcp->ewname;
1118*4436Sstephh 			vmatch(infop, NULL, lnp, anp);
1119*4436Sstephh 			np->u.event.epname = oldepname;
1120*4436Sstephh 			return;
1121*4436Sstephh 		}
1122*4436Sstephh 		if (epmatches) {
1123*4436Sstephh 			/*
1124*4436Sstephh 			 * just first part of names match - do wildcarding
1125*4436Sstephh 			 * by using existing wcp including ewname and also
1126*4436Sstephh 			 * copying as much of pwname as is valid, then start
1127*4436Sstephh 			 * vmatch_event() at start of non-matching section
1128*4436Sstephh 			 */
1129*4436Sstephh 			for (np1 = oldepname, np2 = np->u.event.epname;
1130*4436Sstephh 			    epmatches != 0; epmatches--) {
1131*4436Sstephh 				cp = np1->u.name.cp;
1132*4436Sstephh 				np2->u.name.cp = cp;
1133*4436Sstephh 				np1 = np1->u.name.next;
1134*4436Sstephh 				np2 = np2->u.name.next;
1135*4436Sstephh 			}
1136*4436Sstephh 			wcp->oldepname = np->u.event.epname;
1137*4436Sstephh 			wcp->nptop = np;
1138*4436Sstephh 			vmatch_event(infop, config_child(cp), np2, lnp,
1139*4436Sstephh 			    anp, wcp);
1140*4436Sstephh 			wcp->oldepname = oldepname;
1141*4436Sstephh 			wcp->nptop = oldnptop;
1142*4436Sstephh 			return;
1143*4436Sstephh 		}
1144*4436Sstephh 		/*
1145*4436Sstephh 		 * names do not match - allocate a new wcp
1146*4436Sstephh 		 */
1147*4436Sstephh 		wcp = MALLOC(sizeof (struct wildcardinfo));
1148*4436Sstephh 		wcp->next = wcproot;
1149*4436Sstephh 		wcproot = wcp;
1150*4436Sstephh 		wcp->nptop = np;
1151*4436Sstephh 		wcp->oldepname = np->u.event.epname;
1152*4436Sstephh 		wcp->ewname = NULL;
1153*4436Sstephh 
1154186Sdb35262 		vmatch_event(infop, config_child(infop->croot),
1155*4436Sstephh 		    np->u.event.epname, lnp, anp, wcp);
1156*4436Sstephh 
1157*4436Sstephh 		wcproot = wcp->next;
1158*4436Sstephh 		FREE(wcp);
11590Sstevel@tonic-gate 		break;
11600Sstevel@tonic-gate 	}
11610Sstevel@tonic-gate 	case T_LIST:
11620Sstevel@tonic-gate 		ASSERT(lnp == NULL);
1163*4436Sstephh 		vmatch(infop, np->u.expr.right, np->u.expr.left, anp);
11640Sstevel@tonic-gate 		break;
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	case T_ARROW:
11670Sstevel@tonic-gate 		ASSERT(lnp == NULL && anp == NULL);
1168*4436Sstephh 		vmatch(infop, np->u.arrow.rhs, NULL, np->u.arrow.lhs);
11690Sstevel@tonic-gate 		break;
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 	default:
11720Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
11730Sstevel@tonic-gate 		    "vmatch: unexpected type: %s",
11740Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
11750Sstevel@tonic-gate 	}
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate static void
11790Sstevel@tonic-gate cp_reset(struct node *np)
11800Sstevel@tonic-gate {
11810Sstevel@tonic-gate 	if (np == NULL)
11820Sstevel@tonic-gate 		return;
11830Sstevel@tonic-gate 	switch (np->t) {
11840Sstevel@tonic-gate 	case T_NAME:
11850Sstevel@tonic-gate 		np->u.name.cp = NULL;
11860Sstevel@tonic-gate 		cp_reset(np->u.name.next);
11870Sstevel@tonic-gate 		break;
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 	case T_LIST:
11900Sstevel@tonic-gate 		cp_reset(np->u.expr.left);
11910Sstevel@tonic-gate 		cp_reset(np->u.expr.right);
11920Sstevel@tonic-gate 		break;
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	case T_ARROW:
11950Sstevel@tonic-gate 		cp_reset(np->u.arrow.lhs);
11960Sstevel@tonic-gate 		cp_reset(np->u.arrow.rhs);
11970Sstevel@tonic-gate 		break;
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	case T_EVENT:
12000Sstevel@tonic-gate 		cp_reset(np->u.event.epname);
12010Sstevel@tonic-gate 		break;
12020Sstevel@tonic-gate 	}
12030Sstevel@tonic-gate }
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate /*
12060Sstevel@tonic-gate  * itree_create -- apply the current config to the current parse tree
12070Sstevel@tonic-gate  *
12080Sstevel@tonic-gate  * returns a lut mapping fully-instance-qualified names to struct events.
12090Sstevel@tonic-gate  *
12100Sstevel@tonic-gate  */
12110Sstevel@tonic-gate struct lut *
12120Sstevel@tonic-gate itree_create(struct config *croot)
12130Sstevel@tonic-gate {
12140Sstevel@tonic-gate 	struct lut *retval;
12150Sstevel@tonic-gate 	struct node *propnp;
1216*4436Sstephh 	extern int alloc_total();
1217*4436Sstephh 	int init_size;
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	Ninfo.lut = NULL;
12200Sstevel@tonic-gate 	Ninfo.croot = croot;
1221*4436Sstephh 	init_size = alloc_total();
1222*4436Sstephh 	out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size);
12230Sstevel@tonic-gate 	for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
12240Sstevel@tonic-gate 		struct node *anp = propnp->u.stmt.np;
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 		ASSERTeq(anp->t, T_ARROW, ptree_nodetype2str);
12270Sstevel@tonic-gate 
1228*4436Sstephh 		if (!anp->u.arrow.needed)
1229*4436Sstephh 			continue;
12300Sstevel@tonic-gate 		Ninfo.anp = anp;
12310Sstevel@tonic-gate 		Ninfo.ex = NULL;
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 		generate_arrownp(anp);
1234*4436Sstephh 		vmatch(&Ninfo, anp, NULL, NULL);
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 		if (Ninfo.ex) {
12370Sstevel@tonic-gate 			lut_free(Ninfo.ex, iterinfo_destructor, NULL);
12380Sstevel@tonic-gate 			Ninfo.ex = NULL;
12390Sstevel@tonic-gate 		}
12400Sstevel@tonic-gate 		cp_reset(anp);
12410Sstevel@tonic-gate 	}
12420Sstevel@tonic-gate 
1243*4436Sstephh 	out(O_ALTFP|O_STAMP, "itree_create added %d bytes",
1244*4436Sstephh 	    alloc_total() - init_size);
12450Sstevel@tonic-gate 	retval = Ninfo.lut;
12460Sstevel@tonic-gate 	Ninfo.lut = NULL;
12470Sstevel@tonic-gate 	return (retval);
12480Sstevel@tonic-gate }
12490Sstevel@tonic-gate 
1250*4436Sstephh /*
1251*4436Sstephh  * initial first pass of the rules.
1252*4436Sstephh  * We don't use the config at all. Just check the last part of the pathname
1253*4436Sstephh  * in the rules. If this matches the last part of the pathname in the first
1254*4436Sstephh  * ereport, then set pathname to the pathname in the ereport. If not then
1255*4436Sstephh  * set pathname to just the last part of pathname with instance number 0.
1256*4436Sstephh  * Constraints are ignored and all nork values are set to 0. If after all that
1257*4436Sstephh  * any rules can still not be associated with the ereport, then they are set
1258*4436Sstephh  * to not needed in prune_propagations() and ignored in the real itree_create()
1259*4436Sstephh  * which follows.
1260*4436Sstephh  */
1261*4436Sstephh 
1262*4436Sstephh static struct event *
1263*4436Sstephh add_event_dummy(struct node *np, const struct ipath *ipp)
1264*4436Sstephh {
1265*4436Sstephh 	struct event *ret;
1266*4436Sstephh 	struct event searchevent;	/* just used for searching */
1267*4436Sstephh 	extern struct ipath *ipath_dummy(struct node *, struct ipath *);
1268*4436Sstephh 
1269*4436Sstephh 	searchevent.enode = np;
1270*4436Sstephh 	searchevent.ipp = ipath_dummy(np->u.event.epname, (struct ipath *)ipp);
1271*4436Sstephh 	if ((ret = lut_lookup(Ninfo.lut, (void *)&searchevent,
1272*4436Sstephh 	    (lut_cmp)event_cmp)) != NULL)
1273*4436Sstephh 		return (ret);
1274*4436Sstephh 
1275*4436Sstephh 	ret = alloc_xmalloc(sizeof (*ret));
1276*4436Sstephh 	bzero(ret, sizeof (*ret));
1277*4436Sstephh 	ret->t = np->u.event.ename->u.name.t;
1278*4436Sstephh 	ret->enode = np;
1279*4436Sstephh 	ret->ipp = searchevent.ipp;
1280*4436Sstephh 	Ninfo.lut = lut_add(Ninfo.lut, (void *)ret, (void *)ret,
1281*4436Sstephh 	    (lut_cmp)event_cmp);
1282*4436Sstephh 	return (ret);
1283*4436Sstephh }
1284*4436Sstephh 
1285*4436Sstephh /*ARGSUSED*/
1286*4436Sstephh struct lut *
1287*4436Sstephh itree_create_dummy(const char *e0class, const struct ipath *e0ipp)
1288*4436Sstephh {
1289*4436Sstephh 	struct node *propnp;
1290*4436Sstephh 	struct event *frome, *toe;
1291*4436Sstephh 	struct bubble *frombp, *tobp;
1292*4436Sstephh 	struct arrow *arrowp;
1293*4436Sstephh 	struct node *src, *dst, *slst, *dlst, *arrownp, *oldarrownp;
1294*4436Sstephh 	int gen = 0;
1295*4436Sstephh 	extern int alloc_total();
1296*4436Sstephh 	int init_size;
1297*4436Sstephh 
1298*4436Sstephh 	Ninfo.lut = NULL;
1299*4436Sstephh 	init_size = alloc_total();
1300*4436Sstephh 	out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size);
1301*4436Sstephh 	for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
1302*4436Sstephh 		arrownp = propnp->u.stmt.np;
1303*4436Sstephh 		while (arrownp) {
1304*4436Sstephh 			gen++;
1305*4436Sstephh 			dlst = arrownp->u.arrow.rhs;
1306*4436Sstephh 			slst = arrownp->u.arrow.lhs;
1307*4436Sstephh 			oldarrownp = arrownp;
1308*4436Sstephh 			if (slst->t == T_ARROW) {
1309*4436Sstephh 				arrownp = slst;
1310*4436Sstephh 				slst = slst->u.arrow.rhs;
1311*4436Sstephh 			} else {
1312*4436Sstephh 				arrownp = NULL;
1313*4436Sstephh 			}
1314*4436Sstephh 			while (slst) {
1315*4436Sstephh 				if (slst->t == T_LIST) {
1316*4436Sstephh 					src = slst->u.expr.right;
1317*4436Sstephh 					slst = slst->u.expr.left;
1318*4436Sstephh 				} else {
1319*4436Sstephh 					src = slst;
1320*4436Sstephh 					slst = NULL;
1321*4436Sstephh 				}
1322*4436Sstephh 				frome = add_event_dummy(src, e0ipp);
1323*4436Sstephh 				frombp = itree_add_bubble(frome, B_FROM, 0, 0);
1324*4436Sstephh 				while (dlst) {
1325*4436Sstephh 					if (dlst->t == T_LIST) {
1326*4436Sstephh 						dst = dlst->u.expr.right;
1327*4436Sstephh 						dlst = dlst->u.expr.left;
1328*4436Sstephh 					} else {
1329*4436Sstephh 						dst = dlst;
1330*4436Sstephh 						dlst = NULL;
1331*4436Sstephh 					}
1332*4436Sstephh 					arrowp = alloc_xmalloc(
1333*4436Sstephh 					    sizeof (struct arrow));
1334*4436Sstephh 					bzero(arrowp, sizeof (struct arrow));
1335*4436Sstephh 					arrowp->pnode = oldarrownp;
1336*4436Sstephh 					toe = add_event_dummy(dst, e0ipp);
1337*4436Sstephh 					tobp = itree_add_bubble(toe, B_TO, 0,
1338*4436Sstephh 					    gen);
1339*4436Sstephh 					arrowp->tail = frombp;
1340*4436Sstephh 					arrowp->head = tobp;
1341*4436Sstephh 					add_arrow(frombp, arrowp);
1342*4436Sstephh 					add_arrow(tobp, arrowp);
1343*4436Sstephh 					arrow_add_within(arrowp,
1344*4436Sstephh 					    dst->u.event.declp->u.stmt.np->
1345*4436Sstephh 					    u.event.eexprlist);
1346*4436Sstephh 					arrow_add_within(arrowp,
1347*4436Sstephh 					    dst->u.event.eexprlist);
1348*4436Sstephh 				}
1349*4436Sstephh 			}
1350*4436Sstephh 		}
1351*4436Sstephh 	}
1352*4436Sstephh 	out(O_ALTFP|O_STAMP, "itree_create added %d bytes",
1353*4436Sstephh 	    alloc_total() - init_size);
1354*4436Sstephh 	return (Ninfo.lut);
1355*4436Sstephh }
1356*4436Sstephh 
13570Sstevel@tonic-gate void
13580Sstevel@tonic-gate itree_free(struct lut *lutp)
13590Sstevel@tonic-gate {
1360*4436Sstephh 	int init_size;
1361*4436Sstephh 
1362*4436Sstephh 	init_size = alloc_total();
1363*4436Sstephh 	out(O_ALTFP|O_STAMP, "start itree_free");
13640Sstevel@tonic-gate 	lut_free(lutp, itree_destructor, NULL);
1365*4436Sstephh 	out(O_ALTFP|O_STAMP, "itree_free freed %d bytes",
1366*4436Sstephh 	    init_size - alloc_total());
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate 
13691865Sdilpreet void
13701865Sdilpreet itree_prune(struct lut *lutp)
13711865Sdilpreet {
1372*4436Sstephh 	int init_size;
13730Sstevel@tonic-gate 
1374*4436Sstephh 	init_size = alloc_total();
1375*4436Sstephh 	out(O_ALTFP|O_STAMP, "start itree_prune");
1376*4436Sstephh 	lut_walk(lutp, itree_pruner, NULL);
1377*4436Sstephh 	out(O_ALTFP|O_STAMP, "itree_prune freed %d bytes",
1378*4436Sstephh 	    init_size - alloc_total());
13790Sstevel@tonic-gate }
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate void
13820Sstevel@tonic-gate itree_pevent_brief(int flags, struct event *ep)
13830Sstevel@tonic-gate {
13840Sstevel@tonic-gate 	ASSERT(ep != NULL);
13850Sstevel@tonic-gate 	ASSERT(ep->enode != NULL);
13860Sstevel@tonic-gate 	ASSERT(ep->ipp != NULL);
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	ipath_print(flags, ep->enode->u.event.ename->u.name.s, ep->ipp);
13890Sstevel@tonic-gate }
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate /*ARGSUSED*/
13920Sstevel@tonic-gate static void
13930Sstevel@tonic-gate itree_pevent(struct event *lhs, struct event *ep, void *arg)
13940Sstevel@tonic-gate {
13950Sstevel@tonic-gate 	struct plut_wlk_data propd;
13960Sstevel@tonic-gate 	struct bubble *bp;
13970Sstevel@tonic-gate 	int flags = (int)arg;
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 	itree_pevent_brief(flags, ep);
14000Sstevel@tonic-gate 	if (ep->t == N_EREPORT)
14010Sstevel@tonic-gate 		out(flags, " (count %d)", ep->count);
14020Sstevel@tonic-gate 	else
14030Sstevel@tonic-gate 		out(flags, NULL);
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 	if (ep->props) {
14060Sstevel@tonic-gate 		propd.flags = flags;
14070Sstevel@tonic-gate 		propd.first = 1;
14080Sstevel@tonic-gate 		out(flags, "Properties:");
14090Sstevel@tonic-gate 		lut_walk(ep->props, ptree_plut, (void *)&propd);
14100Sstevel@tonic-gate 	}
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
14130Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
14140Sstevel@tonic-gate 		/* Print only TO bubbles in this loop */
14150Sstevel@tonic-gate 		if (bp->t != B_TO)
14160Sstevel@tonic-gate 			continue;
14170Sstevel@tonic-gate 		itree_pbubble(flags, bp);
14180Sstevel@tonic-gate 	}
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
14210Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
14220Sstevel@tonic-gate 		/* Print only INHIBIT bubbles in this loop */
14230Sstevel@tonic-gate 		if (bp->t != B_INHIBIT)
14240Sstevel@tonic-gate 			continue;
14250Sstevel@tonic-gate 		itree_pbubble(flags, bp);
14260Sstevel@tonic-gate 	}
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
14290Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
14300Sstevel@tonic-gate 		/* Print only FROM bubbles in this loop */
14310Sstevel@tonic-gate 		if (bp->t != B_FROM)
14320Sstevel@tonic-gate 			continue;
14330Sstevel@tonic-gate 		itree_pbubble(flags, bp);
14340Sstevel@tonic-gate 	}
14350Sstevel@tonic-gate }
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate static void
14380Sstevel@tonic-gate itree_pbubble(int flags, struct bubble *bp)
14390Sstevel@tonic-gate {
14400Sstevel@tonic-gate 	struct constraintlist *cp;
14410Sstevel@tonic-gate 	struct arrowlist *ap;
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	ASSERT(bp != NULL);
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 	out(flags|O_NONL, "   ");
14460Sstevel@tonic-gate 	if (bp->mark)
14470Sstevel@tonic-gate 		out(flags|O_NONL, "*");
14480Sstevel@tonic-gate 	else
14490Sstevel@tonic-gate 		out(flags|O_NONL, " ");
14500Sstevel@tonic-gate 	if (bp->t == B_FROM)
14510Sstevel@tonic-gate 		out(flags|O_NONL, "N=%d to:", bp->nork);
14520Sstevel@tonic-gate 	else if (bp->t == B_TO)
14530Sstevel@tonic-gate 		out(flags|O_NONL, "K=%d from:", bp->nork);
14540Sstevel@tonic-gate 	else
14550Sstevel@tonic-gate 		out(flags|O_NONL, "K=%d masked from:", bp->nork);
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate 	if (bp->t == B_TO || bp->t == B_INHIBIT) {
14580Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
14590Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
14600Sstevel@tonic-gate 			ASSERT(ap->arrowp->head == bp);
14610Sstevel@tonic-gate 			ASSERT(ap->arrowp->tail != NULL);
14620Sstevel@tonic-gate 			ASSERT(ap->arrowp->tail->myevent != NULL);
14630Sstevel@tonic-gate 			out(flags|O_NONL, " ");
14640Sstevel@tonic-gate 			itree_pevent_brief(flags, ap->arrowp->tail->myevent);
14650Sstevel@tonic-gate 		}
14660Sstevel@tonic-gate 		out(flags, NULL);
14670Sstevel@tonic-gate 		return;
14680Sstevel@tonic-gate 	}
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	for (ap = itree_next_arrow(bp, NULL); ap;
14710Sstevel@tonic-gate 	    ap = itree_next_arrow(bp, ap)) {
14720Sstevel@tonic-gate 		ASSERT(ap->arrowp->tail == bp);
14730Sstevel@tonic-gate 		ASSERT(ap->arrowp->head != NULL);
14740Sstevel@tonic-gate 		ASSERT(ap->arrowp->head->myevent != NULL);
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 		out(flags|O_NONL, " ");
14770Sstevel@tonic-gate 		itree_pevent_brief(flags, ap->arrowp->head->myevent);
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 		out(flags|O_NONL, " ");
14800Sstevel@tonic-gate 		ptree_timeval(flags, &ap->arrowp->mindelay);
14810Sstevel@tonic-gate 		out(flags|O_NONL, ",");
14820Sstevel@tonic-gate 		ptree_timeval(flags, &ap->arrowp->maxdelay);
14830Sstevel@tonic-gate 
14840Sstevel@tonic-gate 		/* Display anything from the propogation node? */
14850Sstevel@tonic-gate 		out(O_VERB3|O_NONL, " <%s:%d>",
14860Sstevel@tonic-gate 		    ap->arrowp->pnode->file, ap->arrowp->pnode->line);
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 		if (itree_next_constraint(ap->arrowp, NULL))
14890Sstevel@tonic-gate 			out(flags|O_NONL, " {");
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 		for (cp = itree_next_constraint(ap->arrowp, NULL); cp;
14920Sstevel@tonic-gate 		    cp = itree_next_constraint(ap->arrowp, cp)) {
14930Sstevel@tonic-gate 			ptree(flags, cp->cnode, 1, 0);
14940Sstevel@tonic-gate 			if (itree_next_constraint(ap->arrowp, cp))
14950Sstevel@tonic-gate 				out(flags|O_NONL, ", ");
14960Sstevel@tonic-gate 		}
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 		if (itree_next_constraint(ap->arrowp, NULL))
14990Sstevel@tonic-gate 			out(flags|O_NONL, "}");
15000Sstevel@tonic-gate 	}
15010Sstevel@tonic-gate 	out(flags, NULL);
15020Sstevel@tonic-gate }
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate void
15050Sstevel@tonic-gate itree_ptree(int flags, struct lut *itp)
15060Sstevel@tonic-gate {
15070Sstevel@tonic-gate 	lut_walk(itp, (lut_cb)itree_pevent, (void *)flags);
15080Sstevel@tonic-gate }
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate /*ARGSUSED*/
15110Sstevel@tonic-gate static void
15120Sstevel@tonic-gate itree_destructor(void *left, void *right, void *arg)
15130Sstevel@tonic-gate {
15140Sstevel@tonic-gate 	struct event *ep = (struct event *)right;
15150Sstevel@tonic-gate 	struct bubble *nextbub, *bub;
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	/* Free the properties */
15181865Sdilpreet 	if (ep->props)
15191865Sdilpreet 		lut_free(ep->props, instances_destructor, NULL);
15200Sstevel@tonic-gate 
15211414Scindi 	/* Free the payload properties */
15221865Sdilpreet 	if (ep->payloadprops)
15231865Sdilpreet 		lut_free(ep->payloadprops, payloadprops_destructor, NULL);
15241414Scindi 
15250Sstevel@tonic-gate 	/* Free my bubbles */
15260Sstevel@tonic-gate 	for (bub = ep->bubbles; bub != NULL; ) {
15270Sstevel@tonic-gate 		nextbub = bub->next;
15280Sstevel@tonic-gate 		/*
15290Sstevel@tonic-gate 		 * Free arrows if they are FROM me.  Free arrowlists on
15300Sstevel@tonic-gate 		 * other types of bubbles (but not the attached arrows,
15310Sstevel@tonic-gate 		 * which will be freed when we free the originating
15320Sstevel@tonic-gate 		 * bubble.
15330Sstevel@tonic-gate 		 */
15340Sstevel@tonic-gate 		if (bub->t == B_FROM)
15350Sstevel@tonic-gate 			itree_free_arrowlists(bub, 1);
15360Sstevel@tonic-gate 		else
15370Sstevel@tonic-gate 			itree_free_arrowlists(bub, 0);
15380Sstevel@tonic-gate 		itree_free_bubble(bub);
15390Sstevel@tonic-gate 		bub = nextbub;
15400Sstevel@tonic-gate 	}
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	if (ep->nvp != NULL)
15430Sstevel@tonic-gate 		nvlist_free(ep->nvp);
1544*4436Sstephh 	alloc_xfree(ep, sizeof (*ep));
15450Sstevel@tonic-gate }
15460Sstevel@tonic-gate 
15471865Sdilpreet /*ARGSUSED*/
15481865Sdilpreet static void
15491865Sdilpreet itree_pruner(void *left, void *right, void *arg)
15501865Sdilpreet {
15511865Sdilpreet 	struct event *ep = (struct event *)right;
15521865Sdilpreet 	struct bubble *nextbub, *bub;
15531865Sdilpreet 
15541865Sdilpreet 	if (ep->keep_in_tree)
15551865Sdilpreet 		return;
15561865Sdilpreet 
15571865Sdilpreet 	/* Free the properties */
15581865Sdilpreet 	lut_free(ep->props, instances_destructor, NULL);
15591865Sdilpreet 
15601865Sdilpreet 	/* Free the payload properties */
15611865Sdilpreet 	lut_free(ep->payloadprops, payloadprops_destructor, NULL);
15621865Sdilpreet 
15631865Sdilpreet 	/* Free my bubbles */
15641865Sdilpreet 	for (bub = ep->bubbles; bub != NULL; ) {
15651865Sdilpreet 		nextbub = bub->next;
15661865Sdilpreet 		itree_prune_arrowlists(bub);
15671865Sdilpreet 		itree_free_bubble(bub);
15681865Sdilpreet 		bub = nextbub;
15691865Sdilpreet 	}
15701865Sdilpreet 
15711865Sdilpreet 	if (ep->nvp != NULL)
15721865Sdilpreet 		nvlist_free(ep->nvp);
15731865Sdilpreet 	ep->props = NULL;
15741865Sdilpreet 	ep->payloadprops = NULL;
15751865Sdilpreet 	ep->bubbles = NULL;
15761865Sdilpreet 	ep->nvp = NULL;
15771865Sdilpreet }
15781865Sdilpreet 
15790Sstevel@tonic-gate static void
15800Sstevel@tonic-gate itree_free_bubble(struct bubble *freeme)
15810Sstevel@tonic-gate {
1582*4436Sstephh 	alloc_xfree(freeme, sizeof (*freeme));
15830Sstevel@tonic-gate }
15840Sstevel@tonic-gate 
15850Sstevel@tonic-gate static struct bubble *
15860Sstevel@tonic-gate itree_add_bubble(struct event *eventp, enum bubbletype btype, int nork, int gen)
15870Sstevel@tonic-gate {
15880Sstevel@tonic-gate 	struct bubble *prev = NULL;
15890Sstevel@tonic-gate 	struct bubble *curr;
15900Sstevel@tonic-gate 	struct bubble *newb;
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	/* Use existing bubbles as appropriate when possible */
15930Sstevel@tonic-gate 	for (curr = eventp->bubbles;
15940Sstevel@tonic-gate 	    curr != NULL;
15950Sstevel@tonic-gate 	    prev = curr, curr = curr->next) {
15960Sstevel@tonic-gate 		if (btype == B_TO && curr->t == B_TO) {
15970Sstevel@tonic-gate 			/* see if an existing "to" bubble works for us */
15980Sstevel@tonic-gate 			if (gen == curr->gen)
15990Sstevel@tonic-gate 				return (curr);	/* matched gen number */
16000Sstevel@tonic-gate 			else if (nork == 1 && curr->nork == 1) {
16010Sstevel@tonic-gate 				curr->gen = gen;
16020Sstevel@tonic-gate 				return (curr);	/* coalesce K==1 bubbles */
16030Sstevel@tonic-gate 			}
16040Sstevel@tonic-gate 		} else if (btype == B_FROM && curr->t == B_FROM) {
16050Sstevel@tonic-gate 			/* see if an existing "from" bubble works for us */
16060Sstevel@tonic-gate 			if ((nork == N_IS_ALL && curr->nork == N_IS_ALL) ||
16070Sstevel@tonic-gate 			    (nork == 0 && curr->nork == 0))
16080Sstevel@tonic-gate 				return (curr);
16090Sstevel@tonic-gate 		}
16100Sstevel@tonic-gate 	}
16110Sstevel@tonic-gate 
1612*4436Sstephh 	newb = alloc_xmalloc(sizeof (struct bubble));
16130Sstevel@tonic-gate 	newb->next = NULL;
16140Sstevel@tonic-gate 	newb->t = btype;
16150Sstevel@tonic-gate 	newb->myevent = eventp;
16160Sstevel@tonic-gate 	newb->nork = nork;
16170Sstevel@tonic-gate 	newb->mark = 0;
16180Sstevel@tonic-gate 	newb->gen = gen;
16190Sstevel@tonic-gate 	newb->arrows = NULL;
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 	if (prev == NULL)
16220Sstevel@tonic-gate 		eventp->bubbles = newb;
16230Sstevel@tonic-gate 	else
16240Sstevel@tonic-gate 		prev->next = newb;
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 	return (newb);
16270Sstevel@tonic-gate }
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate struct bubble *
16300Sstevel@tonic-gate itree_next_bubble(struct event *eventp, struct bubble *last)
16310Sstevel@tonic-gate {
16320Sstevel@tonic-gate 	struct bubble *next;
16330Sstevel@tonic-gate 
16340Sstevel@tonic-gate 	for (;;) {
16350Sstevel@tonic-gate 		if (last != NULL)
16360Sstevel@tonic-gate 			next = last->next;
16370Sstevel@tonic-gate 		else
16380Sstevel@tonic-gate 			next = eventp->bubbles;
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 		if (next == NULL || next->arrows != NULL)
16410Sstevel@tonic-gate 			return (next);
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 		/* bubble was empty, skip it */
16440Sstevel@tonic-gate 		last = next;
16450Sstevel@tonic-gate 	}
16460Sstevel@tonic-gate }
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate static void
16490Sstevel@tonic-gate add_arrow(struct bubble *bp, struct arrow *ap)
16500Sstevel@tonic-gate {
16510Sstevel@tonic-gate 	struct arrowlist *prev = NULL;
16520Sstevel@tonic-gate 	struct arrowlist *curr;
16530Sstevel@tonic-gate 	struct arrowlist *newal;
16540Sstevel@tonic-gate 
1655*4436Sstephh 	newal = alloc_xmalloc(sizeof (struct arrowlist));
16560Sstevel@tonic-gate 	bzero(newal, sizeof (struct arrowlist));
16570Sstevel@tonic-gate 	newal->arrowp = ap;
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	curr = itree_next_arrow(bp, NULL);
16600Sstevel@tonic-gate 	while (curr != NULL) {
16610Sstevel@tonic-gate 		prev = curr;
16620Sstevel@tonic-gate 		curr = itree_next_arrow(bp, curr);
16630Sstevel@tonic-gate 	}
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate 	if (prev == NULL)
16660Sstevel@tonic-gate 		bp->arrows = newal;
16670Sstevel@tonic-gate 	else
16680Sstevel@tonic-gate 		prev->next = newal;
16690Sstevel@tonic-gate }
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate static struct arrow *
1672*4436Sstephh itree_add_arrow(struct node *apnode, struct node *fromevent,
1673*4436Sstephh     struct node *toevent, struct lut *ex)
16740Sstevel@tonic-gate {
16750Sstevel@tonic-gate 	struct arrow *newa;
16760Sstevel@tonic-gate 
1677*4436Sstephh 	newa = alloc_xmalloc(sizeof (struct arrow));
16781414Scindi 	bzero(newa, sizeof (struct arrow));
16790Sstevel@tonic-gate 	newa->pnode = apnode;
16800Sstevel@tonic-gate 	newa->constraints = NULL;
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 	/*
16830Sstevel@tonic-gate 	 *  Set default delays, then try to re-set them from
16840Sstevel@tonic-gate 	 *  any within() constraints.
16850Sstevel@tonic-gate 	 */
16860Sstevel@tonic-gate 	newa->mindelay = newa->maxdelay = 0ULL;
16870Sstevel@tonic-gate 	if (itree_set_arrow_traits(newa, fromevent, toevent, ex) == 0) {
1688*4436Sstephh 		alloc_xfree(newa, sizeof (struct arrow));
16890Sstevel@tonic-gate 		return (NULL);
16900Sstevel@tonic-gate 	}
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate 	return (newa);
16930Sstevel@tonic-gate }
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate /* returns false if traits show that arrow should not be added after all */
16960Sstevel@tonic-gate static int
16970Sstevel@tonic-gate itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
16980Sstevel@tonic-gate     struct node *toev, struct lut *ex)
16990Sstevel@tonic-gate {
1700*4436Sstephh 	struct node *events[] = { NULL, NULL, NULL };
17010Sstevel@tonic-gate 	struct node *newc = NULL;
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate 	ASSERTeq(fromev->t, T_EVENT, ptree_nodetype2str);
17040Sstevel@tonic-gate 	ASSERTeq(toev->t, T_EVENT, ptree_nodetype2str);
17050Sstevel@tonic-gate 
17060Sstevel@tonic-gate 	/*
17070Sstevel@tonic-gate 	 * search for the within values first on the declaration of
17080Sstevel@tonic-gate 	 * the destination event, and then on the prop.  this allows
17090Sstevel@tonic-gate 	 * one to specify a "default" within by putting it on the
17100Sstevel@tonic-gate 	 * declaration,  but then allow overriding on the prop statement.
17110Sstevel@tonic-gate 	 */
17120Sstevel@tonic-gate 	arrow_add_within(ap, toev->u.event.declp->u.stmt.np->u.event.eexprlist);
17130Sstevel@tonic-gate 	arrow_add_within(ap, toev->u.event.eexprlist);
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 	/*
17160Sstevel@tonic-gate 	 * handle any global constraints inherited from the
17170Sstevel@tonic-gate 	 * "fromev" event's declaration
17180Sstevel@tonic-gate 	 */
17190Sstevel@tonic-gate 	ASSERT(fromev->u.event.declp != NULL);
17200Sstevel@tonic-gate 	ASSERT(fromev->u.event.declp->u.stmt.np != NULL);
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate #ifdef	notdef
17230Sstevel@tonic-gate 	/* XXX not quite ready to evaluate constraints from decls yet */
17240Sstevel@tonic-gate 	if (fromev->u.event.declp->u.stmt.np->u.event.eexprlist)
17250Sstevel@tonic-gate 		(void) itree_add_constraint(ap,
17260Sstevel@tonic-gate 		    fromev->u.event.declp->u.stmt.np->u.event.eexprlist);
17270Sstevel@tonic-gate #endif	/* notdef */
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 	/* handle constraints on the from event in the prop statement */
1730*4436Sstephh 	events[0] = fromev;
1731*4436Sstephh 	events[1] = toev;
1732*4436Sstephh 	if (eval_potential(fromev->u.event.eexprlist, ex, events, &newc,
17332318Sstephh 	    Ninfo.croot) == 0)
17340Sstevel@tonic-gate 		return (0);		/* constraint disallows arrow */
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate 	/*
17370Sstevel@tonic-gate 	 * handle any global constraints inherited from the
17380Sstevel@tonic-gate 	 * "toev" event's declaration
17390Sstevel@tonic-gate 	 */
17400Sstevel@tonic-gate 	ASSERT(toev->u.event.declp != NULL);
17410Sstevel@tonic-gate 	ASSERT(toev->u.event.declp->u.stmt.np != NULL);
17420Sstevel@tonic-gate 
17430Sstevel@tonic-gate #ifdef	notdef
17440Sstevel@tonic-gate 	/* XXX not quite ready to evaluate constraints from decls yet */
17450Sstevel@tonic-gate 	if (toev->u.event.declp->u.stmt.np->u.event.eexprlist)
17460Sstevel@tonic-gate 		(void) itree_add_constraint(ap,
17470Sstevel@tonic-gate 		    toev->u.event.declp->u.stmt.np->u.event.eexprlist);
17480Sstevel@tonic-gate #endif	/* notdef */
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 	/* handle constraints on the to event in the prop statement */
1751*4436Sstephh 	events[0] = toev;
1752*4436Sstephh 	events[1] = fromev;
1753*4436Sstephh 	if (eval_potential(toev->u.event.eexprlist, ex, events, &newc,
17542318Sstephh 	    Ninfo.croot) == 0) {
17551865Sdilpreet 		if (newc != NULL)
17561865Sdilpreet 			tree_free(newc);
17570Sstevel@tonic-gate 		return (0);		/* constraint disallows arrow */
17581865Sdilpreet 	}
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	/* if we came up with any deferred constraints, add them to arrow */
1761*4436Sstephh 	if (newc != NULL) {
1762*4436Sstephh 		out(O_ALTFP|O_VERB3, "(deferred constraints)");
17631414Scindi 		(void) itree_add_constraint(ap, iexpr(newc));
1764*4436Sstephh 	}
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	return (1);	/* constraints allow arrow */
17670Sstevel@tonic-gate }
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate /*
17700Sstevel@tonic-gate  * Set within() constraint.  If the constraint were set multiple times,
17710Sstevel@tonic-gate  * the last one would "win".
17720Sstevel@tonic-gate  */
17730Sstevel@tonic-gate static void
17740Sstevel@tonic-gate arrow_add_within(struct arrow *ap, struct node *xpr)
17750Sstevel@tonic-gate {
17760Sstevel@tonic-gate 	struct node *arglist;
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate 	/* end of expressions list */
17790Sstevel@tonic-gate 	if (xpr == NULL)
17800Sstevel@tonic-gate 		return;
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 	switch (xpr->t) {
17830Sstevel@tonic-gate 	case T_LIST:
17840Sstevel@tonic-gate 		arrow_add_within(ap, xpr->u.expr.left);
17850Sstevel@tonic-gate 		arrow_add_within(ap, xpr->u.expr.right);
17860Sstevel@tonic-gate 		return;
17870Sstevel@tonic-gate 	case T_FUNC:
17880Sstevel@tonic-gate 		if (xpr->u.func.s != L_within)
17890Sstevel@tonic-gate 			return;
17900Sstevel@tonic-gate 		arglist = xpr->u.func.arglist;
17910Sstevel@tonic-gate 		switch (arglist->t) {
17920Sstevel@tonic-gate 		case T_TIMEVAL:
17930Sstevel@tonic-gate 			ap->mindelay = 0;
17940Sstevel@tonic-gate 			ap->maxdelay = arglist->u.ull;
17950Sstevel@tonic-gate 			break;
17960Sstevel@tonic-gate 		case T_NAME:
17970Sstevel@tonic-gate 			ASSERT(arglist->u.name.s == L_infinity);
17980Sstevel@tonic-gate 			ap->mindelay = 0;
17990Sstevel@tonic-gate 			ap->maxdelay = TIMEVAL_EVENTUALLY;
18000Sstevel@tonic-gate 			break;
18010Sstevel@tonic-gate 		case T_LIST:
18020Sstevel@tonic-gate 			ASSERT(arglist->u.expr.left->t == T_TIMEVAL);
18030Sstevel@tonic-gate 			ap->mindelay = arglist->u.expr.left->u.ull;
18040Sstevel@tonic-gate 			switch (arglist->u.expr.right->t) {
18050Sstevel@tonic-gate 			case T_TIMEVAL:
18060Sstevel@tonic-gate 				ap->maxdelay = arglist->u.ull;
18070Sstevel@tonic-gate 				break;
18080Sstevel@tonic-gate 			case T_NAME:
18090Sstevel@tonic-gate 				ASSERT(arglist->u.expr.right->u.name.s ==
18100Sstevel@tonic-gate 				    L_infinity);
18110Sstevel@tonic-gate 				ap->maxdelay = TIMEVAL_EVENTUALLY;
18120Sstevel@tonic-gate 				break;
18130Sstevel@tonic-gate 			default:
18140Sstevel@tonic-gate 				out(O_DIE, "within: unexpected 2nd arg type");
18150Sstevel@tonic-gate 			}
18160Sstevel@tonic-gate 			break;
18170Sstevel@tonic-gate 		default:
18180Sstevel@tonic-gate 			out(O_DIE, "within: unexpected 1st arg type");
18190Sstevel@tonic-gate 		}
18200Sstevel@tonic-gate 		break;
18210Sstevel@tonic-gate 	default:
18220Sstevel@tonic-gate 		return;
18230Sstevel@tonic-gate 	}
18240Sstevel@tonic-gate }
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate static void
18270Sstevel@tonic-gate itree_free_arrowlists(struct bubble *bubp, int arrows_too)
18280Sstevel@tonic-gate {
18290Sstevel@tonic-gate 	struct arrowlist *al, *nal;
18300Sstevel@tonic-gate 
18310Sstevel@tonic-gate 	al = bubp->arrows;
18320Sstevel@tonic-gate 	while (al != NULL) {
18330Sstevel@tonic-gate 		nal = al->next;
18340Sstevel@tonic-gate 		if (arrows_too) {
18350Sstevel@tonic-gate 			itree_free_constraints(al->arrowp);
1836*4436Sstephh 			alloc_xfree(al->arrowp, sizeof (struct arrow));
18370Sstevel@tonic-gate 		}
1838*4436Sstephh 		alloc_xfree(al, sizeof (*al));
18390Sstevel@tonic-gate 		al = nal;
18400Sstevel@tonic-gate 	}
18410Sstevel@tonic-gate }
18420Sstevel@tonic-gate 
18431865Sdilpreet static void
18441865Sdilpreet itree_delete_arrow(struct bubble *bubp, struct arrow *arrow)
18451865Sdilpreet {
18461865Sdilpreet 	struct arrowlist *al, *oal;
18471865Sdilpreet 
18481865Sdilpreet 	al = bubp->arrows;
18491865Sdilpreet 	if (al->arrowp == arrow) {
18501865Sdilpreet 		bubp->arrows = al->next;
1851*4436Sstephh 		alloc_xfree(al, sizeof (*al));
18521865Sdilpreet 		return;
18531865Sdilpreet 	}
18541865Sdilpreet 	while (al != NULL) {
18551865Sdilpreet 		oal = al;
18561865Sdilpreet 		al = al->next;
18571865Sdilpreet 		ASSERT(al != NULL);
18581865Sdilpreet 		if (al->arrowp == arrow) {
18591865Sdilpreet 			oal->next = al->next;
1860*4436Sstephh 			alloc_xfree(al, sizeof (*al));
18611865Sdilpreet 			return;
18621865Sdilpreet 		}
18631865Sdilpreet 	}
18641865Sdilpreet }
18651865Sdilpreet 
18661865Sdilpreet static void
18671865Sdilpreet itree_prune_arrowlists(struct bubble *bubp)
18681865Sdilpreet {
18691865Sdilpreet 	struct arrowlist *al, *nal;
18701865Sdilpreet 
18711865Sdilpreet 	al = bubp->arrows;
18721865Sdilpreet 	while (al != NULL) {
18731865Sdilpreet 		nal = al->next;
18741865Sdilpreet 		if (bubp->t == B_FROM)
18751865Sdilpreet 			itree_delete_arrow(al->arrowp->head, al->arrowp);
18761865Sdilpreet 		else
18771865Sdilpreet 			itree_delete_arrow(al->arrowp->tail, al->arrowp);
18781865Sdilpreet 		itree_free_constraints(al->arrowp);
1879*4436Sstephh 		alloc_xfree(al->arrowp, sizeof (struct arrow));
1880*4436Sstephh 		alloc_xfree(al, sizeof (*al));
18811865Sdilpreet 		al = nal;
18821865Sdilpreet 	}
18831865Sdilpreet }
18841865Sdilpreet 
18850Sstevel@tonic-gate struct arrowlist *
18860Sstevel@tonic-gate itree_next_arrow(struct bubble *bubble, struct arrowlist *last)
18870Sstevel@tonic-gate {
18880Sstevel@tonic-gate 	struct arrowlist *next;
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate 	if (last != NULL)
18910Sstevel@tonic-gate 		next = last->next;
18920Sstevel@tonic-gate 	else
18930Sstevel@tonic-gate 		next = bubble->arrows;
18940Sstevel@tonic-gate 	return (next);
18950Sstevel@tonic-gate }
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate static struct constraintlist *
18980Sstevel@tonic-gate itree_add_constraint(struct arrow *arrowp, struct node *c)
18990Sstevel@tonic-gate {
19000Sstevel@tonic-gate 	struct constraintlist *prev = NULL;
19010Sstevel@tonic-gate 	struct constraintlist *curr;
19020Sstevel@tonic-gate 	struct constraintlist *newc;
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate 	for (curr = arrowp->constraints;
19050Sstevel@tonic-gate 	    curr != NULL;
1906*4436Sstephh 	    prev = curr, curr = curr->next)
1907*4436Sstephh 		;
19080Sstevel@tonic-gate 
1909*4436Sstephh 	newc = alloc_xmalloc(sizeof (struct constraintlist));
19100Sstevel@tonic-gate 	newc->next = NULL;
19110Sstevel@tonic-gate 	newc->cnode = c;
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 	if (prev == NULL)
19140Sstevel@tonic-gate 		arrowp->constraints = newc;
19150Sstevel@tonic-gate 	else
19160Sstevel@tonic-gate 		prev->next = newc;
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 	return (newc);
19190Sstevel@tonic-gate }
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate struct constraintlist *
19220Sstevel@tonic-gate itree_next_constraint(struct arrow *arrowp, struct constraintlist *last)
19230Sstevel@tonic-gate {
19240Sstevel@tonic-gate 	struct constraintlist *next;
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 	if (last != NULL)
19270Sstevel@tonic-gate 		next = last->next;
19280Sstevel@tonic-gate 	else
19290Sstevel@tonic-gate 		next = arrowp->constraints;
19300Sstevel@tonic-gate 	return (next);
19310Sstevel@tonic-gate }
19320Sstevel@tonic-gate 
19330Sstevel@tonic-gate static void
19340Sstevel@tonic-gate itree_free_constraints(struct arrow *ap)
19350Sstevel@tonic-gate {
19360Sstevel@tonic-gate 	struct constraintlist *cl, *ncl;
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate 	cl = ap->constraints;
19390Sstevel@tonic-gate 	while (cl != NULL) {
19400Sstevel@tonic-gate 		ncl = cl->next;
19410Sstevel@tonic-gate 		ASSERT(cl->cnode != NULL);
19421414Scindi 		if (!iexpr_cached(cl->cnode))
19431414Scindi 			tree_free(cl->cnode);
19441865Sdilpreet 		else
19451865Sdilpreet 			iexpr_free(cl->cnode);
1946*4436Sstephh 		alloc_xfree(cl, sizeof (*cl));
19470Sstevel@tonic-gate 		cl = ncl;
19480Sstevel@tonic-gate 	}
19490Sstevel@tonic-gate }
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate const char *
19520Sstevel@tonic-gate itree_bubbletype2str(enum bubbletype t)
19530Sstevel@tonic-gate {
19540Sstevel@tonic-gate 	static char buf[100];
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	switch (t) {
19570Sstevel@tonic-gate 	case B_FROM:	return L_from;
19580Sstevel@tonic-gate 	case B_TO:	return L_to;
19590Sstevel@tonic-gate 	case B_INHIBIT:	return L_inhibit;
19600Sstevel@tonic-gate 	default:
19610Sstevel@tonic-gate 		(void) sprintf(buf, "[unexpected bubbletype: %d]", t);
19620Sstevel@tonic-gate 		return (buf);
19630Sstevel@tonic-gate 	}
19640Sstevel@tonic-gate }
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate /*
19670Sstevel@tonic-gate  * itree_fini -- clean up any half-built itrees
19680Sstevel@tonic-gate  */
19690Sstevel@tonic-gate void
19700Sstevel@tonic-gate itree_fini(void)
19710Sstevel@tonic-gate {
19720Sstevel@tonic-gate 	if (Ninfo.lut != NULL) {
19730Sstevel@tonic-gate 		itree_free(Ninfo.lut);
19740Sstevel@tonic-gate 		Ninfo.lut = NULL;
19750Sstevel@tonic-gate 	}
19760Sstevel@tonic-gate 	if (Ninfo.ex) {
19770Sstevel@tonic-gate 		lut_free(Ninfo.ex, iterinfo_destructor, NULL);
19780Sstevel@tonic-gate 		Ninfo.ex = NULL;
19790Sstevel@tonic-gate 	}
19800Sstevel@tonic-gate }
1981