xref: /onnv-gate/usr/src/cmd/fm/modules/common/eversholt/itree.c (revision 10146:226bcade3f94)
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 /*
239874SStephen.Hanson@Sun.COM  * Copyright 2009 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 #include <stdio.h>
320Sstevel@tonic-gate #include <ctype.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <strings.h>
350Sstevel@tonic-gate #include "alloc.h"
360Sstevel@tonic-gate #include "out.h"
370Sstevel@tonic-gate #include "stable.h"
380Sstevel@tonic-gate #include "literals.h"
390Sstevel@tonic-gate #include "lut.h"
400Sstevel@tonic-gate #include "tree.h"
410Sstevel@tonic-gate #include "ptree.h"
420Sstevel@tonic-gate #include "itree.h"
430Sstevel@tonic-gate #include "ipath.h"
441414Scindi #include "iexpr.h"
450Sstevel@tonic-gate #include "eval.h"
460Sstevel@tonic-gate #include "config.h"
470Sstevel@tonic-gate 
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate  * struct info contains the state we keep when expanding a prop statement
500Sstevel@tonic-gate  * as part of constructing the instance tree.  state kept in struct info
510Sstevel@tonic-gate  * is the non-recursive stuff -- the stuff that doesn't need to be on
520Sstevel@tonic-gate  * the stack.  the rest of the state that is passed between all the
530Sstevel@tonic-gate  * mutually recursive functions, is required to be on the stack since
540Sstevel@tonic-gate  * we need to backtrack and recurse as we do the instance tree construction.
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate struct info {
570Sstevel@tonic-gate 	struct lut *lut;
580Sstevel@tonic-gate 	struct node *anp;	/* arrow np */
590Sstevel@tonic-gate 	struct lut *ex;		/* dictionary of explicit iterators */
600Sstevel@tonic-gate 	struct config *croot;
610Sstevel@tonic-gate } Ninfo;
620Sstevel@tonic-gate 
630Sstevel@tonic-gate /*
640Sstevel@tonic-gate  * struct wildcardinfo is used to track wildcarded portions of paths.
650Sstevel@tonic-gate  *
660Sstevel@tonic-gate  * for example, if the epname of an event is "c/d" and the path "a/b/c/d"
670Sstevel@tonic-gate  * exists, the wildcard path ewname is filled in with the path "a/b".  when
680Sstevel@tonic-gate  * matching is done, epname is temporarily replaced with the concatenation
694436Sstephh  * of ewname and epname.
700Sstevel@tonic-gate  *
710Sstevel@tonic-gate  * a linked list of these structs is used to track the expansion of each
720Sstevel@tonic-gate  * event node as it is processed in vmatch() --> vmatch_event() calls.
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate struct wildcardinfo {
750Sstevel@tonic-gate 	struct node *nptop;		/* event node fed to vmatch */
760Sstevel@tonic-gate 	struct node *oldepname;		/* epname without the wildcard part */
774436Sstephh 	struct node *ewname;		/* wildcard path */
78*10146SStephen.Hanson@Sun.COM 	int got_wc_hz;
790Sstevel@tonic-gate 	struct wildcardinfo *next;
800Sstevel@tonic-gate };
810Sstevel@tonic-gate 
824436Sstephh static struct wildcardinfo *wcproot = NULL;
834436Sstephh 
844436Sstephh static void vmatch(struct info *infop, struct node *np, struct node *lnp,
854436Sstephh     struct node *anp);
860Sstevel@tonic-gate static void hmatch(struct info *infop, struct node *np, struct node *nextnp);
87*10146SStephen.Hanson@Sun.COM static void hmatch_event(struct info *infop, struct node *eventnp,
88*10146SStephen.Hanson@Sun.COM     struct node *epname, struct config *ncp, struct node *nextnp, int rematch);
890Sstevel@tonic-gate static void itree_pbubble(int flags, struct bubble *bp);
901865Sdilpreet static void itree_pruner(void *left, void *right, void *arg);
910Sstevel@tonic-gate static void itree_destructor(void *left, void *right, void *arg);
920Sstevel@tonic-gate static int itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
930Sstevel@tonic-gate     struct node *toev, struct lut *ex);
940Sstevel@tonic-gate static void itree_free_arrowlists(struct bubble *bubp, int arrows_too);
951865Sdilpreet static void itree_prune_arrowlists(struct bubble *bubp);
960Sstevel@tonic-gate static void arrow_add_within(struct arrow *ap, struct node *xpr);
974436Sstephh static struct arrow *itree_add_arrow(struct node *apnode,
984436Sstephh     struct node *fromevent, struct node *toevent, struct lut *ex);
994436Sstephh static struct event *find_or_add_event(struct info *infop, struct node *np);
1004436Sstephh static void add_arrow(struct bubble *bp, struct arrow *ap);
1010Sstevel@tonic-gate static struct constraintlist *itree_add_constraint(struct arrow *arrowp,
1020Sstevel@tonic-gate     struct node *c);
1030Sstevel@tonic-gate static struct bubble *itree_add_bubble(struct event *eventp,
1040Sstevel@tonic-gate     enum bubbletype btype, int nork, int gen);
1050Sstevel@tonic-gate static void itree_free_bubble(struct bubble *freeme);
1060Sstevel@tonic-gate static void itree_free_constraints(struct arrow *ap);
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * the following struct contains the state we build up during
1100Sstevel@tonic-gate  * vertical and horizontal expansion so that generate()
1110Sstevel@tonic-gate  * has everything it needs to construct the appropriate arrows.
1120Sstevel@tonic-gate  * after setting up the state by calling:
1130Sstevel@tonic-gate  *	generate_arrownp()
1140Sstevel@tonic-gate  *	generate_nork()
1150Sstevel@tonic-gate  *	generate_new()
1160Sstevel@tonic-gate  *	generate_from()
1170Sstevel@tonic-gate  *	generate_to()
1180Sstevel@tonic-gate  * the actual arrow generation is done by calling:
1190Sstevel@tonic-gate  *	generate()
1200Sstevel@tonic-gate  */
1210Sstevel@tonic-gate static struct {
1220Sstevel@tonic-gate 	int generation;		/* generation number of arrow set */
1237197Sstephh 	int matched;		/* number of matches */
1240Sstevel@tonic-gate 	struct node *arrownp;	/* top-level parse tree for arrow */
1250Sstevel@tonic-gate 	int n;			/* n value associated with arrow */
1260Sstevel@tonic-gate 	int k;			/* k value associated with arrow */
1270Sstevel@tonic-gate 	struct node *fromnp;	/* left-hand-side event in parse tree */
1280Sstevel@tonic-gate 	struct node *tonp;	/* right-hand-side event in parse tree */
1290Sstevel@tonic-gate 	struct event *frome;	/* left-hand-side event in instance tree */
1300Sstevel@tonic-gate 	struct event *toe;	/* right-hand-side event in instance tree */
1310Sstevel@tonic-gate 	struct bubble *frombp;	/* bubble arrow comes from */
1320Sstevel@tonic-gate 	struct bubble *tobp;	/* bubble arrow goes to */
1330Sstevel@tonic-gate } G;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate static void
generate_arrownp(struct node * arrownp)1360Sstevel@tonic-gate generate_arrownp(struct node *arrownp)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate 	G.arrownp = arrownp;
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate static void
generate_nork(int n,int k)1420Sstevel@tonic-gate generate_nork(int n, int k)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate 	G.n = n;
1450Sstevel@tonic-gate 	G.k = k;
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate static void
generate_new(void)1490Sstevel@tonic-gate generate_new(void)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate 	G.generation++;
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate static void
generate_from(struct node * fromeventnp)1554436Sstephh generate_from(struct node *fromeventnp)
1560Sstevel@tonic-gate {
1574436Sstephh 	G.frombp = NULL;
1580Sstevel@tonic-gate 	G.fromnp = fromeventnp;
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static void
generate_to(struct node * toeventnp)1624436Sstephh generate_to(struct node *toeventnp)
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate 	G.tonp = toeventnp;
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate static void
generate(struct info * infop)1684436Sstephh generate(struct info *infop)
1690Sstevel@tonic-gate {
1704436Sstephh 	struct arrow *arrowp;
1714436Sstephh 
1720Sstevel@tonic-gate 	ASSERT(G.arrownp != NULL);
1730Sstevel@tonic-gate 	ASSERT(G.fromnp != NULL);
1740Sstevel@tonic-gate 	ASSERT(G.tonp != NULL);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL, "        Arrow \"");
1770Sstevel@tonic-gate 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp);
1780Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL, "\" -> \"");
1790Sstevel@tonic-gate 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp);
1804436Sstephh 	out(O_ALTFP|O_VERB3|O_NONL, "\" ");
1810Sstevel@tonic-gate 
1824436Sstephh 	arrowp = itree_add_arrow(G.arrownp, G.fromnp, G.tonp, infop->ex);
1834436Sstephh 	if (arrowp == NULL) {
1844436Sstephh 		out(O_ALTFP|O_VERB3, "(prevented by constraints)");
1850Sstevel@tonic-gate 	} else {
1864436Sstephh 		out(O_ALTFP|O_VERB3, "");
1874436Sstephh 		if (!G.frombp) {
1884436Sstephh 			G.frome = find_or_add_event(infop, G.fromnp);
1894436Sstephh 			G.frombp = itree_add_bubble(G.frome, B_FROM, G.n, 0);
1904436Sstephh 		}
1914436Sstephh 		G.toe = find_or_add_event(infop, G.tonp);
1924436Sstephh 		G.tobp = itree_add_bubble(G.toe, B_TO, G.k, G.generation);
1934436Sstephh 		arrowp->tail = G.frombp;
1944436Sstephh 		arrowp->head = G.tobp;
1954436Sstephh 		add_arrow(G.frombp, arrowp);
1964436Sstephh 		add_arrow(G.tobp, arrowp);
1970Sstevel@tonic-gate 	}
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate enum childnode_action {
2010Sstevel@tonic-gate 	CN_NONE,
2020Sstevel@tonic-gate 	CN_DUP
2030Sstevel@tonic-gate };
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate static struct node *
tname_dup(struct node * namep,enum childnode_action act)2060Sstevel@tonic-gate tname_dup(struct node *namep, enum childnode_action act)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate 	struct node *retp = NULL;
2090Sstevel@tonic-gate 	const char *file;
2100Sstevel@tonic-gate 	int line;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	if (namep == NULL)
2130Sstevel@tonic-gate 		return (NULL);
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	file = namep->file;
2160Sstevel@tonic-gate 	line = namep->line;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	for (; namep != NULL; namep = namep->u.name.next) {
2190Sstevel@tonic-gate 		struct node *newnp = newnode(T_NAME, file, line);
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 		newnp->u.name.t = namep->u.name.t;
2220Sstevel@tonic-gate 		newnp->u.name.s = namep->u.name.s;
2230Sstevel@tonic-gate 		newnp->u.name.last = newnp;
2240Sstevel@tonic-gate 		newnp->u.name.it = namep->u.name.it;
2250Sstevel@tonic-gate 		newnp->u.name.cp = namep->u.name.cp;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 		if (act == CN_DUP) {
2280Sstevel@tonic-gate 			struct node *npc;
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 			npc = namep->u.name.child;
2310Sstevel@tonic-gate 			if (npc != NULL) {
2320Sstevel@tonic-gate 				switch (npc->t) {
2330Sstevel@tonic-gate 				case T_NUM:
2340Sstevel@tonic-gate 					newnp->u.name.child =
2354436Sstephh 					    newnode(T_NUM, file, line);
2360Sstevel@tonic-gate 					newnp->u.name.child->u.ull =
2374436Sstephh 					    npc->u.ull;
2380Sstevel@tonic-gate 					break;
2390Sstevel@tonic-gate 				case T_NAME:
2400Sstevel@tonic-gate 					newnp->u.name.child =
2414436Sstephh 					    tree_name(npc->u.name.s,
2424436Sstephh 					    npc->u.name.it, file, line);
2430Sstevel@tonic-gate 					break;
2440Sstevel@tonic-gate 				default:
2450Sstevel@tonic-gate 					out(O_DIE, "tname_dup: "
2460Sstevel@tonic-gate 					    "invalid child type %s",
2470Sstevel@tonic-gate 					    ptree_nodetype2str(npc->t));
2480Sstevel@tonic-gate 				}
2490Sstevel@tonic-gate 			}
2500Sstevel@tonic-gate 		}
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 		if (retp == NULL) {
2530Sstevel@tonic-gate 			retp = newnp;
2540Sstevel@tonic-gate 		} else {
2550Sstevel@tonic-gate 			retp->u.name.last->u.name.next = newnp;
2560Sstevel@tonic-gate 			retp->u.name.last = newnp;
2570Sstevel@tonic-gate 		}
2580Sstevel@tonic-gate 	}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	return (retp);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate struct prop_wlk_data {
2640Sstevel@tonic-gate 	struct lut *props;
2650Sstevel@tonic-gate 	struct node *epname;
2660Sstevel@tonic-gate };
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate static struct lut *props2instance(struct node *, struct node *);
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate /*
2710Sstevel@tonic-gate  * let oldepname be a subset of epname.  return the subsection of epname
2720Sstevel@tonic-gate  * that ends with oldepname.  make each component in the path explicitly
2730Sstevel@tonic-gate  * instanced (i.e., with a T_NUM child).
2740Sstevel@tonic-gate  */
2750Sstevel@tonic-gate static struct node *
tname_dup_to_epname(struct node * oldepname,struct node * epname)2760Sstevel@tonic-gate tname_dup_to_epname(struct node *oldepname, struct node *epname)
2770Sstevel@tonic-gate {
2780Sstevel@tonic-gate 	struct node *npref, *npend, *np1, *np2;
2790Sstevel@tonic-gate 	struct node *ret = NULL;
2800Sstevel@tonic-gate 	int foundmatch = 0;
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	if (epname == NULL)
2830Sstevel@tonic-gate 		return (NULL);
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	/*
2860Sstevel@tonic-gate 	 * search for the longest path in epname which contains
2870Sstevel@tonic-gate 	 * oldnode->u.event.epname.  set npend to point to just past the
2880Sstevel@tonic-gate 	 * end of this path.
2890Sstevel@tonic-gate 	 */
2900Sstevel@tonic-gate 	npend = NULL;
2910Sstevel@tonic-gate 	for (npref = epname; npref; npref = npref->u.name.next) {
2920Sstevel@tonic-gate 		if (npref->u.name.s == oldepname->u.name.s) {
2930Sstevel@tonic-gate 			for (np1 = npref, np2 = oldepname;
2940Sstevel@tonic-gate 			    np1 != NULL && np2 != NULL;
2950Sstevel@tonic-gate 			    np1 = np1->u.name.next, np2 = np2->u.name.next) {
2960Sstevel@tonic-gate 				if (np1->u.name.s != np2->u.name.s)
2970Sstevel@tonic-gate 					break;
2980Sstevel@tonic-gate 			}
2990Sstevel@tonic-gate 			if (np2 == NULL) {
3000Sstevel@tonic-gate 				foundmatch = 1;
3010Sstevel@tonic-gate 				npend = np1;
3020Sstevel@tonic-gate 				if (np1 == NULL) {
3030Sstevel@tonic-gate 					/* oldepname matched npref up to end */
3040Sstevel@tonic-gate 					break;
3050Sstevel@tonic-gate 				}
3060Sstevel@tonic-gate 			}
3070Sstevel@tonic-gate 		}
3080Sstevel@tonic-gate 	}
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	if (foundmatch == 0) {
3110Sstevel@tonic-gate 		/*
3120Sstevel@tonic-gate 		 * if oldepname could not be found in epname, return a
3130Sstevel@tonic-gate 		 * duplicate of the former.  do not try to instantize
3140Sstevel@tonic-gate 		 * oldepname since it might not be a path.
3150Sstevel@tonic-gate 		 */
3160Sstevel@tonic-gate 		return (tname_dup(oldepname, CN_DUP));
3170Sstevel@tonic-gate 	}
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	/*
3200Sstevel@tonic-gate 	 * dup (epname -- npend).  all children should be T_NUMs.
3210Sstevel@tonic-gate 	 */
3220Sstevel@tonic-gate 	for (npref = epname;
3230Sstevel@tonic-gate 	    ! (npref == NULL || npref == npend);
3240Sstevel@tonic-gate 	    npref = npref->u.name.next) {
3250Sstevel@tonic-gate 		struct node *newnp = newnode(T_NAME, oldepname->file,
3264436Sstephh 		    oldepname->line);
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 		newnp->u.name.t = npref->u.name.t;
3290Sstevel@tonic-gate 		newnp->u.name.s = npref->u.name.s;
3300Sstevel@tonic-gate 		newnp->u.name.last = newnp;
3310Sstevel@tonic-gate 		newnp->u.name.it = npref->u.name.it;
3320Sstevel@tonic-gate 		newnp->u.name.cp = npref->u.name.cp;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 		newnp->u.name.child = newnode(T_NUM, oldepname->file,
3354436Sstephh 		    oldepname->line);
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 		if (npref->u.name.child == NULL ||
3380Sstevel@tonic-gate 		    npref->u.name.child->t != T_NUM) {
3390Sstevel@tonic-gate 			int childnum;
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 			ASSERT(npref->u.name.cp != NULL);
3420Sstevel@tonic-gate 			config_getcompname(npref->u.name.cp, NULL, &childnum);
3430Sstevel@tonic-gate 			newnp->u.name.child->u.ull = childnum;
3440Sstevel@tonic-gate 		} else {
3450Sstevel@tonic-gate 			newnp->u.name.child->u.ull =
3464436Sstephh 			    npref->u.name.child->u.ull;
3470Sstevel@tonic-gate 		}
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 		if (ret == NULL) {
3500Sstevel@tonic-gate 			ret = newnp;
3510Sstevel@tonic-gate 		} else {
3520Sstevel@tonic-gate 			ret->u.name.last->u.name.next = newnp;
3530Sstevel@tonic-gate 			ret->u.name.last = newnp;
3540Sstevel@tonic-gate 		}
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	return (ret);
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate  * restriction: oldnode->u.event.epname has to be equivalent to or a subset
3620Sstevel@tonic-gate  * of epname
3630Sstevel@tonic-gate  */
3640Sstevel@tonic-gate static struct node *
tevent_dup_to_epname(struct node * oldnode,struct node * epname)3650Sstevel@tonic-gate tevent_dup_to_epname(struct node *oldnode, struct node *epname)
3660Sstevel@tonic-gate {
3670Sstevel@tonic-gate 	struct node *ret;
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	ret = newnode(T_EVENT, oldnode->file, oldnode->line);
3700Sstevel@tonic-gate 	ret->u.event.ename = tname_dup(oldnode->u.event.ename, CN_NONE);
3710Sstevel@tonic-gate 	ret->u.event.epname = tname_dup_to_epname(oldnode->u.event.epname,
3724436Sstephh 	    epname);
3730Sstevel@tonic-gate 	return (ret);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate static void
nv_instantiate(void * name,void * val,void * arg)3770Sstevel@tonic-gate nv_instantiate(void *name, void *val, void *arg)
3780Sstevel@tonic-gate {
3790Sstevel@tonic-gate 	struct prop_wlk_data *pd = (struct prop_wlk_data *)arg;
3800Sstevel@tonic-gate 	struct node *orhs = (struct node *)val;
3810Sstevel@tonic-gate 	struct node *nrhs;
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	/* handle engines by instantizing the entire engine */
3840Sstevel@tonic-gate 	if (name == L_engine) {
3850Sstevel@tonic-gate 		ASSERT(orhs->t == T_EVENT);
3860Sstevel@tonic-gate 		ASSERT(orhs->u.event.ename->u.name.t == N_SERD);
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 		/* there are only SERD engines for now */
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 		nrhs = newnode(T_SERD, orhs->file, orhs->line);
3910Sstevel@tonic-gate 		nrhs->u.stmt.np = tevent_dup_to_epname(orhs, pd->epname);
3920Sstevel@tonic-gate 		nrhs->u.stmt.lutp = props2instance(orhs, pd->epname);
3930Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
3940Sstevel@tonic-gate 		return;
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	switch (orhs->t) {
3980Sstevel@tonic-gate 	case T_NUM:
3990Sstevel@tonic-gate 		nrhs = newnode(T_NUM, orhs->file, orhs->line);
4000Sstevel@tonic-gate 		nrhs->u.ull = orhs->u.ull;
4010Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4020Sstevel@tonic-gate 		break;
4030Sstevel@tonic-gate 	case T_TIMEVAL:
4040Sstevel@tonic-gate 		nrhs = newnode(T_TIMEVAL, orhs->file, orhs->line);
4050Sstevel@tonic-gate 		nrhs->u.ull = orhs->u.ull;
4060Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4070Sstevel@tonic-gate 		break;
4080Sstevel@tonic-gate 	case T_NAME:
4090Sstevel@tonic-gate 		nrhs = tname_dup_to_epname(orhs, pd->epname);
4100Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4110Sstevel@tonic-gate 		break;
4120Sstevel@tonic-gate 	case T_EVENT:
4130Sstevel@tonic-gate 		nrhs = tevent_dup_to_epname(orhs, pd->epname);
4140Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4150Sstevel@tonic-gate 		break;
4161414Scindi 	case T_GLOBID:
4171414Scindi 		nrhs = newnode(T_GLOBID, orhs->file, orhs->line);
4181414Scindi 		nrhs->u.globid.s = orhs->u.globid.s;
4191414Scindi 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4201414Scindi 		break;
4211414Scindi 	case T_FUNC:
4221414Scindi 		/* for T_FUNC, we don't duplicate it, just point to node */
4231414Scindi 		pd->props = lut_add(pd->props, name, orhs, NULL);
4241414Scindi 		break;
4250Sstevel@tonic-gate 	default:
4261414Scindi 		out(O_DIE, "unexpected nvpair value type %s",
4270Sstevel@tonic-gate 		    ptree_nodetype2str(((struct node *)val)->t));
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate static struct lut *
props2instance(struct node * eventnp,struct node * epname)4320Sstevel@tonic-gate props2instance(struct node *eventnp, struct node *epname)
4330Sstevel@tonic-gate {
4340Sstevel@tonic-gate 	struct prop_wlk_data pd;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	pd.props = NULL;
4370Sstevel@tonic-gate 	pd.epname = epname;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	ASSERT(eventnp->u.event.declp != NULL);
4400Sstevel@tonic-gate 	lut_walk(eventnp->u.event.declp->u.stmt.lutp, nv_instantiate, &pd);
4410Sstevel@tonic-gate 	return (pd.props);
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate /*ARGSUSED*/
4450Sstevel@tonic-gate static void
instances_destructor(void * left,void * right,void * arg)4460Sstevel@tonic-gate instances_destructor(void *left, void *right, void *arg)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate 	struct node *dn = (struct node *)right;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	if (dn->t == T_SERD) {
4510Sstevel@tonic-gate 		/* we allocated the lut during itree_create(), so free it */
4520Sstevel@tonic-gate 		lut_free(dn->u.stmt.lutp, instances_destructor, NULL);
4530Sstevel@tonic-gate 		dn->u.stmt.lutp = NULL;
4540Sstevel@tonic-gate 	}
4551414Scindi 	if (dn->t != T_FUNC)	/* T_FUNC pointed to original node */
4561414Scindi 		tree_free(dn);
4571414Scindi }
4581414Scindi 
4591414Scindi /*ARGSUSED*/
4601414Scindi static void
payloadprops_destructor(void * left,void * right,void * arg)4611414Scindi payloadprops_destructor(void *left, void *right, void *arg)
4621414Scindi {
4631414Scindi 	FREE(right);
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate 
4667197Sstephh /*ARGSUSED*/
4677197Sstephh static void
serdprops_destructor(void * left,void * right,void * arg)4687197Sstephh serdprops_destructor(void *left, void *right, void *arg)
4697197Sstephh {
4707197Sstephh 	FREE(right);
4717197Sstephh }
4727197Sstephh 
4730Sstevel@tonic-gate /*
4740Sstevel@tonic-gate  * event_cmp -- used via lut_lookup/lut_add on instance tree lut
4750Sstevel@tonic-gate  */
4760Sstevel@tonic-gate static int
event_cmp(struct event * ep1,struct event * ep2)4770Sstevel@tonic-gate event_cmp(struct event *ep1, struct event *ep2)
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate 	int diff;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	if ((diff = ep2->enode->u.event.ename->u.name.s -
4820Sstevel@tonic-gate 	    ep1->enode->u.event.ename->u.name.s) != 0)
4830Sstevel@tonic-gate 		return (diff);
4840Sstevel@tonic-gate 	if ((diff = (char *)ep2->ipp - (char *)ep1->ipp) != 0)
4850Sstevel@tonic-gate 		return (diff);
4860Sstevel@tonic-gate 	return (0);
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate struct event *
itree_lookup(struct lut * itp,const char * ename,const struct ipath * ipp)4910Sstevel@tonic-gate itree_lookup(struct lut *itp, const char *ename, const struct ipath *ipp)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate 	struct event searchevent;	/* just used for searching */
4940Sstevel@tonic-gate 	struct node searcheventnode;
4950Sstevel@tonic-gate 	struct node searchenamenode;
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	searchevent.enode = &searcheventnode;
4980Sstevel@tonic-gate 	searcheventnode.t = T_EVENT;
4990Sstevel@tonic-gate 	searcheventnode.u.event.ename = &searchenamenode;
5000Sstevel@tonic-gate 	searchenamenode.t = T_NAME;
5010Sstevel@tonic-gate 	searchenamenode.u.name.s = ename;
5020Sstevel@tonic-gate 	searchevent.ipp = ipp;
5030Sstevel@tonic-gate 	return (lut_lookup(itp, (void *)&searchevent, (lut_cmp)event_cmp));
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate static struct event *
find_or_add_event(struct info * infop,struct node * np)5070Sstevel@tonic-gate find_or_add_event(struct info *infop, struct node *np)
5080Sstevel@tonic-gate {
5090Sstevel@tonic-gate 	struct event *ret;
5100Sstevel@tonic-gate 	struct event searchevent;	/* just used for searching */
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	ASSERTeq(np->t, T_EVENT, ptree_nodetype2str);
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	searchevent.enode = np;
5150Sstevel@tonic-gate 	searchevent.ipp = ipath(np->u.event.epname);
5160Sstevel@tonic-gate 	if ((ret = lut_lookup(infop->lut, (void *)&searchevent,
5170Sstevel@tonic-gate 	    (lut_cmp)event_cmp)) != NULL)
5180Sstevel@tonic-gate 		return (ret);
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	/* wasn't already in tree, allocate it */
5214436Sstephh 	ret = alloc_xmalloc(sizeof (*ret));
5220Sstevel@tonic-gate 	bzero(ret, sizeof (*ret));
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	ret->t = np->u.event.ename->u.name.t;
5250Sstevel@tonic-gate 	ret->enode = np;
5260Sstevel@tonic-gate 	ret->ipp = searchevent.ipp;
5270Sstevel@tonic-gate 	ret->props = props2instance(np, np->u.event.epname);
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	infop->lut = lut_add(infop->lut, (void *)ret, (void *)ret,
5300Sstevel@tonic-gate 	    (lut_cmp)event_cmp);
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	return (ret);
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate /*
536*10146SStephen.Hanson@Sun.COM  * Used for handling expansions where first part of oldepname is a horizontal
537*10146SStephen.Hanson@Sun.COM  * expansion. Recurses through entire tree. oldepname argument is always the
538*10146SStephen.Hanson@Sun.COM  * full path as in the rules. Once we find a match we go back to using
539*10146SStephen.Hanson@Sun.COM  * hmatch_event to handle the rest.
540*10146SStephen.Hanson@Sun.COM  */
541*10146SStephen.Hanson@Sun.COM static void
hmatch_full_config(struct info * infop,struct node * eventnp,struct node * oldepname,struct config * ncp,struct node * nextnp,struct iterinfo * iterinfop)542*10146SStephen.Hanson@Sun.COM hmatch_full_config(struct info *infop, struct node *eventnp,
543*10146SStephen.Hanson@Sun.COM     struct node *oldepname, struct config *ncp, struct node *nextnp,
544*10146SStephen.Hanson@Sun.COM     struct iterinfo *iterinfop)
545*10146SStephen.Hanson@Sun.COM {
546*10146SStephen.Hanson@Sun.COM 	char *cp_s;
547*10146SStephen.Hanson@Sun.COM 	int cp_num;
548*10146SStephen.Hanson@Sun.COM 	struct config *cp;
549*10146SStephen.Hanson@Sun.COM 	struct node *saved_ewname;
550*10146SStephen.Hanson@Sun.COM 	struct node *saved_epname;
551*10146SStephen.Hanson@Sun.COM 	struct config *pcp, *ocp;
552*10146SStephen.Hanson@Sun.COM 	struct node *cpnode;
553*10146SStephen.Hanson@Sun.COM 	struct node *ewlp, *ewfp;
554*10146SStephen.Hanson@Sun.COM 
555*10146SStephen.Hanson@Sun.COM 	for (cp = ncp; cp; cp = config_next(cp)) {
556*10146SStephen.Hanson@Sun.COM 		config_getcompname(cp, &cp_s, &cp_num);
557*10146SStephen.Hanson@Sun.COM 		if (cp_s == oldepname->u.name.s) {
558*10146SStephen.Hanson@Sun.COM 			/*
559*10146SStephen.Hanson@Sun.COM 			 * Found one.
560*10146SStephen.Hanson@Sun.COM 			 */
561*10146SStephen.Hanson@Sun.COM 			iterinfop->num = cp_num;
562*10146SStephen.Hanson@Sun.COM 
563*10146SStephen.Hanson@Sun.COM 			/*
564*10146SStephen.Hanson@Sun.COM 			 * Need to set ewname, epname for correct node as is
565*10146SStephen.Hanson@Sun.COM 			 * needed by constraint path matching. This code is
566*10146SStephen.Hanson@Sun.COM 			 * similar to that in vmatch_event.
567*10146SStephen.Hanson@Sun.COM 			 */
568*10146SStephen.Hanson@Sun.COM 			saved_ewname = eventnp->u.event.ewname;
569*10146SStephen.Hanson@Sun.COM 			saved_epname = eventnp->u.event.epname;
570*10146SStephen.Hanson@Sun.COM 			ocp = oldepname->u.name.cp;
571*10146SStephen.Hanson@Sun.COM 
572*10146SStephen.Hanson@Sun.COM 			/*
573*10146SStephen.Hanson@Sun.COM 			 * Find correct ewname by walking back up the config
574*10146SStephen.Hanson@Sun.COM 			 * tree adding each name portion as we go.
575*10146SStephen.Hanson@Sun.COM 			 */
576*10146SStephen.Hanson@Sun.COM 			pcp = config_parent(cp);
577*10146SStephen.Hanson@Sun.COM 			eventnp->u.event.ewname = NULL;
578*10146SStephen.Hanson@Sun.COM 			for (; pcp != infop->croot; pcp = config_parent(pcp)) {
579*10146SStephen.Hanson@Sun.COM 				config_getcompname(pcp, &cp_s, &cp_num);
580*10146SStephen.Hanson@Sun.COM 				cpnode = tree_name(cp_s, IT_NONE, NULL, 0);
581*10146SStephen.Hanson@Sun.COM 				cpnode->u.name.child = newnode(T_NUM, NULL, 0);
582*10146SStephen.Hanson@Sun.COM 				cpnode->u.name.child->u.ull = cp_num;
583*10146SStephen.Hanson@Sun.COM 				cpnode->u.name.cp = pcp;
584*10146SStephen.Hanson@Sun.COM 				if (eventnp->u.event.ewname != NULL) {
585*10146SStephen.Hanson@Sun.COM 					cpnode->u.name.next =
586*10146SStephen.Hanson@Sun.COM 					    eventnp->u.event.ewname;
587*10146SStephen.Hanson@Sun.COM 					cpnode->u.name.last =
588*10146SStephen.Hanson@Sun.COM 					    eventnp->u.event.ewname->
589*10146SStephen.Hanson@Sun.COM 					    u.name.last;
590*10146SStephen.Hanson@Sun.COM 				}
591*10146SStephen.Hanson@Sun.COM 				eventnp->u.event.ewname = cpnode;
592*10146SStephen.Hanson@Sun.COM 			}
593*10146SStephen.Hanson@Sun.COM 
594*10146SStephen.Hanson@Sun.COM 			/*
595*10146SStephen.Hanson@Sun.COM 			 * Now create correct epname by duping new ewname
596*10146SStephen.Hanson@Sun.COM 			 * and appending oldepname.
597*10146SStephen.Hanson@Sun.COM 			 */
598*10146SStephen.Hanson@Sun.COM 			ewfp = tname_dup(eventnp->u.event.ewname, CN_DUP);
599*10146SStephen.Hanson@Sun.COM 			ewlp = ewfp->u.name.last;
600*10146SStephen.Hanson@Sun.COM 			ewfp->u.name.last = oldepname->u.name.last;
601*10146SStephen.Hanson@Sun.COM 			ewlp->u.name.next = oldepname;
602*10146SStephen.Hanson@Sun.COM 			oldepname->u.name.cp = cp;
603*10146SStephen.Hanson@Sun.COM 			eventnp->u.event.epname = ewfp;
604*10146SStephen.Hanson@Sun.COM 
605*10146SStephen.Hanson@Sun.COM 			outfl(O_ALTFP|O_VERB3|O_NONL, infop->anp->file,
606*10146SStephen.Hanson@Sun.COM 			    infop->anp->line, "hmatch_full_config: ");
607*10146SStephen.Hanson@Sun.COM 			ptree_name_iter(O_ALTFP|O_VERB3|O_NONL,
608*10146SStephen.Hanson@Sun.COM 			    eventnp->u.event.epname);
609*10146SStephen.Hanson@Sun.COM 			out(O_ALTFP|O_VERB3, NULL);
610*10146SStephen.Hanson@Sun.COM 
611*10146SStephen.Hanson@Sun.COM 			/*
612*10146SStephen.Hanson@Sun.COM 			 * Now complete hmatch.
613*10146SStephen.Hanson@Sun.COM 			 */
614*10146SStephen.Hanson@Sun.COM 			hmatch_event(infop, eventnp, oldepname->u.name.next,
615*10146SStephen.Hanson@Sun.COM 			    config_child(cp), nextnp, 1);
616*10146SStephen.Hanson@Sun.COM 
617*10146SStephen.Hanson@Sun.COM 			/*
618*10146SStephen.Hanson@Sun.COM 			 * set everything back again
619*10146SStephen.Hanson@Sun.COM 			 */
620*10146SStephen.Hanson@Sun.COM 			oldepname->u.name.cp = ocp;
621*10146SStephen.Hanson@Sun.COM 			iterinfop->num = -1;
622*10146SStephen.Hanson@Sun.COM 			ewlp->u.name.next = NULL;
623*10146SStephen.Hanson@Sun.COM 			ewfp->u.name.last = ewlp;
624*10146SStephen.Hanson@Sun.COM 			tree_free(ewfp);
625*10146SStephen.Hanson@Sun.COM 			tree_free(eventnp->u.event.ewname);
626*10146SStephen.Hanson@Sun.COM 			eventnp->u.event.ewname = saved_ewname;
627*10146SStephen.Hanson@Sun.COM 			eventnp->u.event.epname = saved_epname;
628*10146SStephen.Hanson@Sun.COM 		}
629*10146SStephen.Hanson@Sun.COM 		/*
630*10146SStephen.Hanson@Sun.COM 		 * Try the next level down.
631*10146SStephen.Hanson@Sun.COM 		 */
632*10146SStephen.Hanson@Sun.COM 		hmatch_full_config(infop, eventnp,
633*10146SStephen.Hanson@Sun.COM 		    oldepname, config_child(cp), nextnp, iterinfop);
634*10146SStephen.Hanson@Sun.COM 	}
635*10146SStephen.Hanson@Sun.COM }
636*10146SStephen.Hanson@Sun.COM 
637*10146SStephen.Hanson@Sun.COM /*
6380Sstevel@tonic-gate  * hmatch_event -- perform any appropriate horizontal expansion on an event
6390Sstevel@tonic-gate  *
6400Sstevel@tonic-gate  * this routine is used to perform horizontal expansion on both the
6410Sstevel@tonic-gate  * left-hand-side events in a prop, and the right-hand-side events.
6420Sstevel@tonic-gate  * when called to handle a left-side event, nextnp point to the right
6430Sstevel@tonic-gate  * side of the prop that should be passed to hmatch() for each match
6440Sstevel@tonic-gate  * found by horizontal expansion.   when no horizontal expansion exists,
6450Sstevel@tonic-gate  * we will still "match" one event for every event found in the list on
6460Sstevel@tonic-gate  * the left-hand-side of the prop because vmatch() already found that
6470Sstevel@tonic-gate  * there's at least one match during vertical expansion.
6480Sstevel@tonic-gate  */
6490Sstevel@tonic-gate static void
hmatch_event(struct info * infop,struct node * eventnp,struct node * epname,struct config * ncp,struct node * nextnp,int rematch)6500Sstevel@tonic-gate hmatch_event(struct info *infop, struct node *eventnp, struct node *epname,
6510Sstevel@tonic-gate     struct config *ncp, struct node *nextnp, int rematch)
6520Sstevel@tonic-gate {
6530Sstevel@tonic-gate 	if (epname == NULL) {
6540Sstevel@tonic-gate 		/*
6550Sstevel@tonic-gate 		 * end of pathname recursion, either we just located
6560Sstevel@tonic-gate 		 * a left-hand-side event and we're ready to move on
6570Sstevel@tonic-gate 		 * to the expanding the right-hand-side events, or
6580Sstevel@tonic-gate 		 * we're further down the recursion and we just located
6590Sstevel@tonic-gate 		 * a right-hand-side event.  the passed-in parameter
6600Sstevel@tonic-gate 		 * "nextnp" tells us whether we're working on the left
6610Sstevel@tonic-gate 		 * side and need to move on to nextnp, or if nextnp is
6620Sstevel@tonic-gate 		 * NULL, we're working on the right side.
6630Sstevel@tonic-gate 		 */
6640Sstevel@tonic-gate 		if (nextnp) {
6650Sstevel@tonic-gate 			/*
6660Sstevel@tonic-gate 			 * finished a left side expansion, move on to right.
6670Sstevel@tonic-gate 			 * tell generate() what event we just matched so
6680Sstevel@tonic-gate 			 * it can be used at the source of any arrows
6690Sstevel@tonic-gate 			 * we generate as we match events on the right side.
6700Sstevel@tonic-gate 			 */
6714436Sstephh 			generate_from(eventnp);
6720Sstevel@tonic-gate 			hmatch(infop, nextnp, NULL);
6730Sstevel@tonic-gate 		} else {
6740Sstevel@tonic-gate 			/*
6750Sstevel@tonic-gate 			 * finished a right side expansion.  tell generate
6760Sstevel@tonic-gate 			 * the information about the destination and let
6770Sstevel@tonic-gate 			 * it construct the arrows as appropriate.
6780Sstevel@tonic-gate 			 */
6794436Sstephh 			generate_to(eventnp);
6804436Sstephh 			generate(infop);
6810Sstevel@tonic-gate 		}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 		return;
6840Sstevel@tonic-gate 	}
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	ASSERTeq(epname->t, T_NAME, ptree_nodetype2str);
6870Sstevel@tonic-gate 
6887197Sstephh 	if (epname->u.name.cp == NULL)
6897197Sstephh 		return;
6907197Sstephh 
6910Sstevel@tonic-gate 	/*
6920Sstevel@tonic-gate 	 * we only get here when eventnp already has a completely
6930Sstevel@tonic-gate 	 * instanced epname in it already.  so we first recurse
6940Sstevel@tonic-gate 	 * down to the end of the name and as the recursion pops
6950Sstevel@tonic-gate 	 * up, we look for opportunities to advance horizontal
6964436Sstephh 	 * expansions on to the next match.
6970Sstevel@tonic-gate 	 */
6984436Sstephh 	if (epname->u.name.it == IT_HORIZONTAL || rematch) {
6990Sstevel@tonic-gate 		struct config *cp;
7000Sstevel@tonic-gate 		struct config *ocp = epname->u.name.cp;
7010Sstevel@tonic-gate 		char *cp_s;
7020Sstevel@tonic-gate 		int cp_num;
7030Sstevel@tonic-gate 		int ocp_num;
7040Sstevel@tonic-gate 		struct iterinfo *iterinfop = NULL;
7050Sstevel@tonic-gate 		const char *iters;
7064436Sstephh 		int hexpand = 0;
7070Sstevel@tonic-gate 
7084436Sstephh 		if (epname->u.name.it != IT_HORIZONTAL) {
7094436Sstephh 			/*
7104436Sstephh 			 * Ancestor was horizontal though, so must rematch
7114436Sstephh 			 * against the name/num found in vmatch.
7124436Sstephh 			 */
7134436Sstephh 			config_getcompname(ocp, NULL, &ocp_num);
7144436Sstephh 		} else {
7154436Sstephh 			iters = epname->u.name.child->u.name.s;
7164436Sstephh 			if ((iterinfop = lut_lookup(infop->ex,
7174436Sstephh 			    (void *)iters, NULL)) == NULL) {
7184436Sstephh 				/*
7194436Sstephh 				 * do horizontal expansion on this node
7204436Sstephh 				 */
7214436Sstephh 				hexpand = 1;
7224436Sstephh 				iterinfop = alloc_xmalloc(
7234436Sstephh 				    sizeof (struct iterinfo));
7244436Sstephh 				iterinfop->num = -1;
7254436Sstephh 				iterinfop->np = epname;
7264436Sstephh 				infop->ex = lut_add(infop->ex, (void *)iters,
7274436Sstephh 				    iterinfop, NULL);
7284436Sstephh 			} else if (iterinfop->num == -1) {
7294436Sstephh 				hexpand = 1;
7304436Sstephh 			} else {
7314436Sstephh 				/*
7324436Sstephh 				 * This name has already been used in a
7334436Sstephh 				 * horizontal expansion. This time just match it
7344436Sstephh 				 */
7354436Sstephh 				ocp_num = iterinfop->num;
7364436Sstephh 			}
7374436Sstephh 		}
7384436Sstephh 		/*
739*10146SStephen.Hanson@Sun.COM 		 * handle case where this is the first section of oldepname
740*10146SStephen.Hanson@Sun.COM 		 * and it is horizontally expanded. Instead of just looking for
741*10146SStephen.Hanson@Sun.COM 		 * siblings, we want to scan the entire config tree for further
742*10146SStephen.Hanson@Sun.COM 		 * matches.
743*10146SStephen.Hanson@Sun.COM 		 */
744*10146SStephen.Hanson@Sun.COM 		if (epname == eventnp->u.event.oldepname &&
745*10146SStephen.Hanson@Sun.COM 		    epname->u.name.it == IT_HORIZONTAL) {
746*10146SStephen.Hanson@Sun.COM 			/*
747*10146SStephen.Hanson@Sun.COM 			 * Run through config looking for any that match the
748*10146SStephen.Hanson@Sun.COM 			 * name.
749*10146SStephen.Hanson@Sun.COM 			 */
750*10146SStephen.Hanson@Sun.COM 			hmatch_full_config(infop, eventnp, epname,
751*10146SStephen.Hanson@Sun.COM 			    infop->croot, nextnp, iterinfop);
752*10146SStephen.Hanson@Sun.COM 			return;
753*10146SStephen.Hanson@Sun.COM 		}
754*10146SStephen.Hanson@Sun.COM 
755*10146SStephen.Hanson@Sun.COM 		/*
7564436Sstephh 		 * Run through siblings looking for any that match the name.
7574436Sstephh 		 * If hexpand not set then num must also match ocp_num.
7584436Sstephh 		 */
7594436Sstephh 		for (cp = rematch ? ncp : ocp; cp; cp = config_next(cp)) {
7604436Sstephh 			config_getcompname(cp, &cp_s, &cp_num);
7614436Sstephh 			if (cp_s == epname->u.name.s) {
7624436Sstephh 				if (hexpand)
7630Sstevel@tonic-gate 					iterinfop->num = cp_num;
7644436Sstephh 				else if (ocp_num != cp_num)
7654436Sstephh 					continue;
7660Sstevel@tonic-gate 				epname->u.name.cp = cp;
7670Sstevel@tonic-gate 				hmatch_event(infop, eventnp,
7680Sstevel@tonic-gate 				    epname->u.name.next, config_child(cp),
7690Sstevel@tonic-gate 				    nextnp, 1);
7700Sstevel@tonic-gate 			}
7710Sstevel@tonic-gate 		}
7720Sstevel@tonic-gate 		epname->u.name.cp = ocp;
7734436Sstephh 		if (hexpand)
7744436Sstephh 			iterinfop->num = -1;
7754436Sstephh 	} else {
7764436Sstephh 		hmatch_event(infop, eventnp, epname->u.name.next,
7774436Sstephh 		    NULL, nextnp, 0);
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate /*
7820Sstevel@tonic-gate  * hmatch -- check for horizontal expansion matches
7830Sstevel@tonic-gate  *
7840Sstevel@tonic-gate  * np points to the things we're matching (like a T_LIST or a T_EVENT)
7850Sstevel@tonic-gate  * and if we're working on a left-side of a prop, nextnp points to
7860Sstevel@tonic-gate  * the other side of the prop that we'll tackle next when this recursion
7870Sstevel@tonic-gate  * bottoms out.  when all the events in the entire prop arrow have been
7880Sstevel@tonic-gate  * horizontally expanded, generate() will be called to generate the
7890Sstevel@tonic-gate  * actualy arrow.
7900Sstevel@tonic-gate  */
7910Sstevel@tonic-gate static void
hmatch(struct info * infop,struct node * np,struct node * nextnp)7920Sstevel@tonic-gate hmatch(struct info *infop, struct node *np, struct node *nextnp)
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate 	if (np == NULL)
7950Sstevel@tonic-gate 		return;		/* all done */
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	/*
7980Sstevel@tonic-gate 	 * for each item in the list of events (which could just
7990Sstevel@tonic-gate 	 * be a single event, or it could get larger in the loop
8000Sstevel@tonic-gate 	 * below due to horizontal expansion), call hmatch on
8010Sstevel@tonic-gate 	 * the right side and create arrows to each element.
8020Sstevel@tonic-gate 	 */
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	switch (np->t) {
8050Sstevel@tonic-gate 	case T_LIST:
8060Sstevel@tonic-gate 		/* loop through the list */
8070Sstevel@tonic-gate 		if (np->u.expr.left)
8080Sstevel@tonic-gate 			hmatch(infop, np->u.expr.left, nextnp);
8090Sstevel@tonic-gate 		if (np->u.expr.right)
8100Sstevel@tonic-gate 			hmatch(infop, np->u.expr.right, nextnp);
8110Sstevel@tonic-gate 		break;
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	case T_EVENT:
8140Sstevel@tonic-gate 		hmatch_event(infop, np, np->u.event.epname,
8150Sstevel@tonic-gate 		    NULL, nextnp, 0);
8160Sstevel@tonic-gate 		break;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	default:
8190Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
8200Sstevel@tonic-gate 		    "hmatch: unexpected type: %s",
8210Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
8220Sstevel@tonic-gate 	}
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate static int
itree_np2nork(struct node * norknp)8260Sstevel@tonic-gate itree_np2nork(struct node *norknp)
8270Sstevel@tonic-gate {
8280Sstevel@tonic-gate 	if (norknp == NULL)
8290Sstevel@tonic-gate 		return (1);
8300Sstevel@tonic-gate 	else if (norknp->t == T_NAME && norknp->u.name.s == L_A)
8310Sstevel@tonic-gate 		return (-1);	/* our internal version of "all" */
8320Sstevel@tonic-gate 	else if (norknp->t == T_NUM)
8330Sstevel@tonic-gate 		return ((int)norknp->u.ull);
8340Sstevel@tonic-gate 	else
8354436Sstephh 		outfl(O_DIE, norknp->file, norknp->line,
8360Sstevel@tonic-gate 		    "itree_np2nork: internal error type %s",
8370Sstevel@tonic-gate 		    ptree_nodetype2str(norknp->t));
8380Sstevel@tonic-gate 	/*NOTREACHED*/
8391717Swesolows 	return (1);
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate static struct iterinfo *
newiterinfo(int num,struct node * np)8430Sstevel@tonic-gate newiterinfo(int num, struct node *np)
8440Sstevel@tonic-gate {
8454436Sstephh 	struct iterinfo *ret = alloc_xmalloc(sizeof (*ret));
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	ret->num = num;
8480Sstevel@tonic-gate 	ret->np = np;
8490Sstevel@tonic-gate 	return (ret);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate /*ARGSUSED*/
8530Sstevel@tonic-gate static void
iterinfo_destructor(void * left,void * right,void * arg)8540Sstevel@tonic-gate iterinfo_destructor(void *left, void *right, void *arg)
8550Sstevel@tonic-gate {
8560Sstevel@tonic-gate 	struct iterinfo *iterinfop = (struct iterinfo *)right;
8570Sstevel@tonic-gate 
8584436Sstephh 	alloc_xfree(iterinfop, sizeof (*iterinfop));
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate 
8614436Sstephh static void
vmatch_event(struct info * infop,struct config * cp,struct node * np,struct node * lnp,struct node * anp,struct wildcardinfo * wcp)8624436Sstephh vmatch_event(struct info *infop, struct config *cp, struct node *np,
8634436Sstephh 	    struct node *lnp, struct node *anp, struct wildcardinfo *wcp)
864186Sdb35262 {
8654436Sstephh 	char *cp_s;
8664436Sstephh 	int cp_num;
8674436Sstephh 	struct node *ewlp, *ewfp;
8684436Sstephh 	struct config *pcp;
8694436Sstephh 	struct node *cpnode;
8704436Sstephh 	int newewname = 0;
871186Sdb35262 
872*10146SStephen.Hanson@Sun.COM 	/*
873*10146SStephen.Hanson@Sun.COM 	 * handle case where the first section of the path name is horizontally
874*10146SStephen.Hanson@Sun.COM 	 * expanded. The whole expansion is handled by hmatch on the first
875*10146SStephen.Hanson@Sun.COM 	 * match here - so we just skip any subsequent matches here.
876*10146SStephen.Hanson@Sun.COM 	 */
877*10146SStephen.Hanson@Sun.COM 	if (wcp->got_wc_hz == 1)
878*10146SStephen.Hanson@Sun.COM 		return;
879*10146SStephen.Hanson@Sun.COM 
8804436Sstephh 	if (np == NULL) {
881186Sdb35262 		/*
8824436Sstephh 		 * Reached the end of the name. u.name.cp pointers should be set
8834436Sstephh 		 * up for each part of name. From this we can use config tree
8844436Sstephh 		 * to build up the wildcard part of the name (if any).
885186Sdb35262 		 */
8864436Sstephh 		pcp = config_parent(wcp->nptop->u.event.epname->u.name.cp);
8874436Sstephh 		if (pcp == infop->croot) {
8884436Sstephh 			/*
8894436Sstephh 			 * no wildcarding done - move on to next entry
8904436Sstephh 			 */
8914436Sstephh 			wcp->nptop->u.event.ewname = wcp->ewname;
8924436Sstephh 			wcp->nptop->u.event.oldepname = wcp->oldepname;
8934436Sstephh 			vmatch(infop, np, lnp, anp);
894*10146SStephen.Hanson@Sun.COM 			wcp->got_wc_hz = 0;
8954436Sstephh 			return;
8964436Sstephh 		}
8974436Sstephh 		if (wcp->ewname == NULL) {
8984436Sstephh 			/*
8994436Sstephh 			 * ewname not yet set up - do it now
9004436Sstephh 			 */
9014436Sstephh 			newewname = 1;
9024436Sstephh 			for (; pcp != infop->croot; pcp = config_parent(pcp)) {
9034436Sstephh 				config_getcompname(pcp, &cp_s, &cp_num);
9044436Sstephh 				cpnode = tree_name(cp_s, IT_NONE, NULL, 0);
9054436Sstephh 				cpnode->u.name.child = newnode(T_NUM, NULL, 0);
9064436Sstephh 				cpnode->u.name.child->u.ull = cp_num;
9074436Sstephh 				cpnode->u.name.cp = pcp;
9084436Sstephh 				if (wcp->ewname != NULL) {
9094436Sstephh 					cpnode->u.name.next = wcp->ewname;
9104436Sstephh 					cpnode->u.name.last =
9114436Sstephh 					    wcp->ewname->u.name.last;
9124436Sstephh 				}
9134436Sstephh 				wcp->ewname = cpnode;
9144436Sstephh 			}
9154436Sstephh 		}
916186Sdb35262 
917186Sdb35262 		/*
9184436Sstephh 		 * dup ewname and append oldepname
919186Sdb35262 		 */
9204436Sstephh 		ewfp = tname_dup(wcp->ewname, CN_DUP);
9214436Sstephh 		ewlp = ewfp->u.name.last;
9224436Sstephh 		ewfp->u.name.last = wcp->oldepname->u.name.last;
9234436Sstephh 		ewlp->u.name.next = wcp->oldepname;
9244436Sstephh 
9254436Sstephh 		wcp->nptop->u.event.epname = ewfp;
9264436Sstephh 		wcp->nptop->u.event.ewname = wcp->ewname;
9274436Sstephh 		wcp->nptop->u.event.oldepname = wcp->oldepname;
9284436Sstephh 		vmatch(infop, np, lnp, anp);
929*10146SStephen.Hanson@Sun.COM 		wcp->got_wc_hz = 0;
9304436Sstephh 		wcp->nptop->u.event.epname = wcp->oldepname;
931186Sdb35262 
9324436Sstephh 		/*
9334436Sstephh 		 * reduce duped ewname to original then free
9344436Sstephh 		 */
9354436Sstephh 		ewlp->u.name.next = NULL;
9364436Sstephh 		ewfp->u.name.last = ewlp;
9374436Sstephh 		tree_free(ewfp);
938186Sdb35262 
9394436Sstephh 		if (newewname) {
9404436Sstephh 			/*
9414436Sstephh 			 * free ewname if allocated above
9424436Sstephh 			 */
9434436Sstephh 			tree_free(wcp->ewname);
9444436Sstephh 			wcp->ewname = NULL;
9454436Sstephh 		}
9464436Sstephh 		return;
947186Sdb35262 	}
948186Sdb35262 
949186Sdb35262 	/*
9504436Sstephh 	 * We have an np. See if we can match it in this section of
9514436Sstephh 	 * the config tree.
9520Sstevel@tonic-gate 	 */
9530Sstevel@tonic-gate 	if (cp == NULL)
9540Sstevel@tonic-gate 		return;	/* no more config to match against */
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 	for (; cp; cp = config_next(cp)) {
9570Sstevel@tonic-gate 		config_getcompname(cp, &cp_s, &cp_num);
9580Sstevel@tonic-gate 
9594436Sstephh 		if (cp_s == np->u.name.s) {
9600Sstevel@tonic-gate 			/* found a matching component name */
9610Sstevel@tonic-gate 			if (np->u.name.child &&
9620Sstevel@tonic-gate 			    np->u.name.child->t == T_NUM) {
9630Sstevel@tonic-gate 				/*
9640Sstevel@tonic-gate 				 * an explicit instance number was given
9650Sstevel@tonic-gate 				 * in the source.  so only consider this
9660Sstevel@tonic-gate 				 * a configuration match if the number
9670Sstevel@tonic-gate 				 * also matches.
9680Sstevel@tonic-gate 				 */
9690Sstevel@tonic-gate 				if (cp_num != np->u.name.child->u.ull)
9700Sstevel@tonic-gate 					continue;
9710Sstevel@tonic-gate 
9724436Sstephh 			} else if (np->u.name.it != IT_HORIZONTAL) {
9730Sstevel@tonic-gate 				struct iterinfo *iterinfop;
9740Sstevel@tonic-gate 				const char *iters;
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 				/*
9770Sstevel@tonic-gate 				 * vertical iterator.  look it up in
9780Sstevel@tonic-gate 				 * the appropriate lut and if we get
9790Sstevel@tonic-gate 				 * back a value it is either one that we
9800Sstevel@tonic-gate 				 * set earlier, in which case we record
9810Sstevel@tonic-gate 				 * the new value for this iteration and
9820Sstevel@tonic-gate 				 * keep matching, or it is one that was
9830Sstevel@tonic-gate 				 * set by an earlier reference to the
9840Sstevel@tonic-gate 				 * iterator, in which case we only consider
9850Sstevel@tonic-gate 				 * this a configuration match if the number
9860Sstevel@tonic-gate 				 * matches cp_num.
9870Sstevel@tonic-gate 				 */
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 				ASSERT(np->u.name.child != NULL);
9900Sstevel@tonic-gate 				ASSERT(np->u.name.child->t == T_NAME);
9910Sstevel@tonic-gate 				iters = np->u.name.child->u.name.s;
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 				if ((iterinfop = lut_lookup(infop->ex,
9940Sstevel@tonic-gate 				    (void *)iters, NULL)) == NULL) {
9950Sstevel@tonic-gate 					/* we're the first use, record our np */
9960Sstevel@tonic-gate 					infop->ex = lut_add(infop->ex,
9970Sstevel@tonic-gate 					    (void *)iters,
9980Sstevel@tonic-gate 					    newiterinfo(cp_num, np), NULL);
9990Sstevel@tonic-gate 				} else if (np == iterinfop->np) {
10000Sstevel@tonic-gate 					/*
10010Sstevel@tonic-gate 					 * we're the first use, back again
10020Sstevel@tonic-gate 					 * for another iteration.  so update
10030Sstevel@tonic-gate 					 * the num bound to this iterator in
10040Sstevel@tonic-gate 					 * the lut.
10050Sstevel@tonic-gate 					 */
10060Sstevel@tonic-gate 					iterinfop->num = cp_num;
10070Sstevel@tonic-gate 				} else if (cp_num != iterinfop->num) {
10080Sstevel@tonic-gate 					/*
10090Sstevel@tonic-gate 					 * an earlier reference to this
10100Sstevel@tonic-gate 					 * iterator bound it to a different
10110Sstevel@tonic-gate 					 * instance number, so there's no
10120Sstevel@tonic-gate 					 * match here after all.
1013186Sdb35262 					 *
1014186Sdb35262 					 * however, it's possible that this
1015186Sdb35262 					 * component should really be part of
1016186Sdb35262 					 * the wildcard.  we explore this by
1017186Sdb35262 					 * forcing this component into the
1018186Sdb35262 					 * wildcarded section.
1019186Sdb35262 					 *
1020186Sdb35262 					 * for an more details of what's
1021186Sdb35262 					 * going to happen now, see
1022186Sdb35262 					 * comments block below entitled
1023186Sdb35262 					 * "forcing components into
1024186Sdb35262 					 * wildcard path".
10250Sstevel@tonic-gate 					 */
10264436Sstephh 					if (np == wcp->nptop->u.event.epname)
10274436Sstephh 						vmatch_event(infop,
10284436Sstephh 						    config_child(cp), np, lnp,
10294436Sstephh 						    anp, wcp);
10300Sstevel@tonic-gate 					continue;
10310Sstevel@tonic-gate 				}
10320Sstevel@tonic-gate 			}
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 			/*
10354436Sstephh 			 * if this was an IT_HORIZONTAL name, hmatch() will
10364436Sstephh 			 * expand all matches horizontally into a list.
10370Sstevel@tonic-gate 			 * we know the list will contain at least
10380Sstevel@tonic-gate 			 * one element (the one we just matched),
10394436Sstephh 			 * so we just let hmatch_event() do the rest.
10400Sstevel@tonic-gate 			 *
10414436Sstephh 			 * recurse on to next component. Note that
10420Sstevel@tonic-gate 			 * wildcarding is now turned off.
10430Sstevel@tonic-gate 			 */
10444436Sstephh 			np->u.name.cp = cp;
10450Sstevel@tonic-gate 			vmatch_event(infop, config_child(cp), np->u.name.next,
10464436Sstephh 			    lnp, anp, wcp);
10474436Sstephh 			np->u.name.cp = NULL;
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 			/*
1050*10146SStephen.Hanson@Sun.COM 			 * handle case where this is the first section of the
1051*10146SStephen.Hanson@Sun.COM 			 * path name and it is horizontally expanded.
1052*10146SStephen.Hanson@Sun.COM 			 * In this case we want all matching nodes in the config
1053*10146SStephen.Hanson@Sun.COM 			 * to be expanded horizontally - so set got_wc_hz and
1054*10146SStephen.Hanson@Sun.COM 			 * leave all further processing to hmatch.
1055*10146SStephen.Hanson@Sun.COM 			 */
1056*10146SStephen.Hanson@Sun.COM 			if (G.matched && np == wcp->nptop->u.event.epname &&
1057*10146SStephen.Hanson@Sun.COM 			    np->u.name.it == IT_HORIZONTAL)
1058*10146SStephen.Hanson@Sun.COM 				wcp->got_wc_hz = 1;
1059*10146SStephen.Hanson@Sun.COM 
1060*10146SStephen.Hanson@Sun.COM 			/*
1061186Sdb35262 			 * forcing components into wildcard path:
1062186Sdb35262 			 *
1063186Sdb35262 			 * if this component is the first match, force it
1064186Sdb35262 			 * to be part of the wildcarded path and see if we
10654436Sstephh 			 * can get additional matches.
1066186Sdb35262 			 *
1067186Sdb35262 			 * here's an example.  suppose we have the
1068186Sdb35262 			 * definition
1069186Sdb35262 			 *	event foo@x/y
1070186Sdb35262 			 * and configuration
1071186Sdb35262 			 *	a0/x0/y0/a1/x1/y1
1072186Sdb35262 			 *
1073186Sdb35262 			 * the code up to this point will treat "a0" as the
1074186Sdb35262 			 * wildcarded part of the path and "x0/y0" as the
1075186Sdb35262 			 * nonwildcarded part, resulting in the instanced
1076186Sdb35262 			 * event
1077186Sdb35262 			 *	foo@a0/x0/y0
1078186Sdb35262 			 *
1079186Sdb35262 			 * in order to discover the next match (.../x1/y1)
1080186Sdb35262 			 * in the configuration we have to force "x0" into
10814436Sstephh 			 * the wildcarded part of the path.
1082186Sdb35262 			 * by doing so, we discover the wildcarded part
1083186Sdb35262 			 * "a0/x0/y0/a1" and the nonwildcarded part "x1/y1"
1084186Sdb35262 			 *
1085186Sdb35262 			 * the following call to vmatch_event() is also
1086186Sdb35262 			 * needed to properly handle the configuration
1087186Sdb35262 			 *	b0/x0/b1/x1/y1
1088186Sdb35262 			 *
1089186Sdb35262 			 * the recursions into vmatch_event() will start
1090186Sdb35262 			 * off uncovering "b0" as the wildcarded part and
1091186Sdb35262 			 * "x0" as the start of the nonwildcarded path.
1092186Sdb35262 			 * however, the next recursion will not result in a
1093186Sdb35262 			 * match since there is no "y" following "x0".  the
1094186Sdb35262 			 * subsequent match of (wildcard = "b0/x0/b1" and
1095186Sdb35262 			 * nonwildcard = "x1/y1") will be discovered only
1096186Sdb35262 			 * if "x0" is forced to be a part of the wildcarded
1097186Sdb35262 			 * path.
10980Sstevel@tonic-gate 			 */
10994436Sstephh 			if (np == wcp->nptop->u.event.epname)
11004436Sstephh 				vmatch_event(infop, config_child(cp), np, lnp,
11014436Sstephh 				    anp, wcp);
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 			if (np->u.name.it == IT_HORIZONTAL) {
11040Sstevel@tonic-gate 				/*
11050Sstevel@tonic-gate 				 * hmatch() finished iterating through
11060Sstevel@tonic-gate 				 * the configuration as described above, so
11070Sstevel@tonic-gate 				 * don't continue iterating here.
11080Sstevel@tonic-gate 				 */
11090Sstevel@tonic-gate 				return;
11100Sstevel@tonic-gate 			}
11114436Sstephh 		} else if (np == wcp->nptop->u.event.epname) {
11120Sstevel@tonic-gate 			/*
11134436Sstephh 			 * no match - carry on down the tree looking for
11144436Sstephh 			 * wildcarding
11150Sstevel@tonic-gate 			 */
11160Sstevel@tonic-gate 			vmatch_event(infop, config_child(cp), np, lnp, anp,
11174436Sstephh 			    wcp);
11180Sstevel@tonic-gate 		}
11190Sstevel@tonic-gate 	}
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate /*
11230Sstevel@tonic-gate  * vmatch -- find the next vertical expansion match in the config database
11240Sstevel@tonic-gate  *
11250Sstevel@tonic-gate  * this routine is called with three node pointers:
11260Sstevel@tonic-gate  *	 np -- the parse we're matching
11270Sstevel@tonic-gate  *	lnp -- the rest of the list we're currently working on
11280Sstevel@tonic-gate  *	anp -- the rest of the arrow we're currently working on
11290Sstevel@tonic-gate  *
11300Sstevel@tonic-gate  * the expansion matching happens via three types of recursion:
11310Sstevel@tonic-gate  *
11320Sstevel@tonic-gate  *	- when given an arrow, handle the left-side and then recursively
11330Sstevel@tonic-gate  *	  handle the right side (which might be another cascaded arrow).
11340Sstevel@tonic-gate  *
11350Sstevel@tonic-gate  *	- when handling one side of an arrow, recurse through the T_LIST
11360Sstevel@tonic-gate  *	  to get to each event (or just move on to the event if there
11370Sstevel@tonic-gate  *	  is a single event instead of a list)  since the arrow parse
11380Sstevel@tonic-gate  *	  trees recurse left, we actually start with the right-most
11390Sstevel@tonic-gate  *	  event list in the prop statement and work our way towards
11400Sstevel@tonic-gate  *	  the left-most event list.
11410Sstevel@tonic-gate  *
11420Sstevel@tonic-gate  *	- when handling an event, recurse down each component of the
11430Sstevel@tonic-gate  *	  pathname, matching in the config database and recording the
11440Sstevel@tonic-gate  *	  matches in the explicit iterator dictionary as we go.
11450Sstevel@tonic-gate  *
11460Sstevel@tonic-gate  * when the bottom of this matching recursion is met, meaning we have
11470Sstevel@tonic-gate  * set the "cp" pointers on all the names in the entire statement,
11480Sstevel@tonic-gate  * we call hmatch() which does it's own recursion to handle horizontal
11490Sstevel@tonic-gate  * expandsion and then call generate() to generate nodes, bubbles, and
11500Sstevel@tonic-gate  * arrows in the instance tree.  generate() looks at the cp pointers to
11510Sstevel@tonic-gate  * see what instance numbers were matched in the configuration database.
11520Sstevel@tonic-gate  *
11530Sstevel@tonic-gate  * when horizontal expansion appears, vmatch() finds only the first match
11540Sstevel@tonic-gate  * and hmatch() then takes the horizontal expansion through all the other
11550Sstevel@tonic-gate  * matches when generating the arrows in the instance tree.
11560Sstevel@tonic-gate  *
11570Sstevel@tonic-gate  * the "infop" passed down through the recursion contains a dictionary
11580Sstevel@tonic-gate  * of the explicit iterators (all the implicit iterators have been converted
11590Sstevel@tonic-gate  * to explicit iterators when the parse tree was created by tree.c), which
11600Sstevel@tonic-gate  * allows things like this to work correctly:
11610Sstevel@tonic-gate  *
11620Sstevel@tonic-gate  *	prop error.a@x[n]/y/z -> error.b@x/y[n]/z -> error.c@x/y/z[n];
11630Sstevel@tonic-gate  *
11640Sstevel@tonic-gate  * during the top level call, the explicit iterator "n" will match an
11650Sstevel@tonic-gate  * instance number in the config database, and the result will be recorded
11660Sstevel@tonic-gate  * in the explicit iterator dictionary and passed down via "infop".  so
11670Sstevel@tonic-gate  * when the recursive call tries to match y[n] in the config database, it
11680Sstevel@tonic-gate  * will only match the same instance number as x[n] did since the dictionary
11690Sstevel@tonic-gate  * is consulted to see if "n" took on a value already.
11700Sstevel@tonic-gate  *
11710Sstevel@tonic-gate  * at any point during the recursion, match*() can return to indicate
11720Sstevel@tonic-gate  * a match was not found in the config database and that the caller should
11730Sstevel@tonic-gate  * move on to the next potential match, if any.
11740Sstevel@tonic-gate  *
11750Sstevel@tonic-gate  * constraints are completely ignored by match(), so the statement:
11760Sstevel@tonic-gate  *
11770Sstevel@tonic-gate  *	prop error.a@x[n] -> error.b@x[n] {n != 0};
11780Sstevel@tonic-gate  *
11790Sstevel@tonic-gate  * might very well match x[0] if it appears in the config database.  it
11800Sstevel@tonic-gate  * is the generate() routine that takes that match and then decides what
11810Sstevel@tonic-gate  * arrow, if any, should be generated in the instance tree.  generate()
11820Sstevel@tonic-gate  * looks at the explicit iterator dictionary to get values like "n" in
11830Sstevel@tonic-gate  * the above example so that it can evaluate constraints.
11840Sstevel@tonic-gate  *
11850Sstevel@tonic-gate  */
11860Sstevel@tonic-gate static void
vmatch(struct info * infop,struct node * np,struct node * lnp,struct node * anp)11874436Sstephh vmatch(struct info *infop, struct node *np, struct node *lnp, struct node *anp)
11880Sstevel@tonic-gate {
11894436Sstephh 	struct node *np1, *np2, *oldepname, *oldnptop;
11904436Sstephh 	int epmatches;
11914436Sstephh 	struct config *cp;
11924436Sstephh 	struct wildcardinfo *wcp;
11934436Sstephh 
11940Sstevel@tonic-gate 	if (np == NULL) {
11957197Sstephh 		G.matched = 1;
11960Sstevel@tonic-gate 		if (lnp)
11974436Sstephh 			vmatch(infop, lnp, NULL, anp);
11980Sstevel@tonic-gate 		else if (anp)
11994436Sstephh 			vmatch(infop, anp, NULL, NULL);
12000Sstevel@tonic-gate 		else {
12010Sstevel@tonic-gate 			struct node *src;
12020Sstevel@tonic-gate 			struct node *dst;
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 			/* end of vertical match recursion */
12050Sstevel@tonic-gate 			outfl(O_ALTFP|O_VERB3|O_NONL,
12060Sstevel@tonic-gate 			    infop->anp->file, infop->anp->line, "vmatch: ");
12070Sstevel@tonic-gate 			ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, infop->anp);
12080Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3, NULL);
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 			generate_nork(
12110Sstevel@tonic-gate 			    itree_np2nork(infop->anp->u.arrow.nnp),
12120Sstevel@tonic-gate 			    itree_np2nork(infop->anp->u.arrow.knp));
12130Sstevel@tonic-gate 			dst = infop->anp->u.arrow.rhs;
12140Sstevel@tonic-gate 			src = infop->anp->u.arrow.lhs;
12150Sstevel@tonic-gate 			for (;;) {
12160Sstevel@tonic-gate 				generate_new();	/* new set of arrows */
12170Sstevel@tonic-gate 				if (src->t == T_ARROW) {
12180Sstevel@tonic-gate 					hmatch(infop, src->u.arrow.rhs, dst);
12190Sstevel@tonic-gate 					generate_nork(
12200Sstevel@tonic-gate 					    itree_np2nork(src->u.arrow.nnp),
12210Sstevel@tonic-gate 					    itree_np2nork(src->u.arrow.knp));
12220Sstevel@tonic-gate 					dst = src->u.arrow.rhs;
12230Sstevel@tonic-gate 					src = src->u.arrow.lhs;
12240Sstevel@tonic-gate 				} else {
12250Sstevel@tonic-gate 					hmatch(infop, src, dst);
12260Sstevel@tonic-gate 					break;
12270Sstevel@tonic-gate 				}
12280Sstevel@tonic-gate 			}
12290Sstevel@tonic-gate 		}
12300Sstevel@tonic-gate 		return;
12310Sstevel@tonic-gate 	}
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 	switch (np->t) {
12340Sstevel@tonic-gate 	case T_EVENT: {
12354436Sstephh 		epmatches = 0;
12364436Sstephh 		/*
12374436Sstephh 		 * see if we already have a match in the wcps
12384436Sstephh 		 */
12394436Sstephh 		for (wcp = wcproot; wcp; wcp = wcp->next) {
12404436Sstephh 			oldepname = wcp->oldepname;
12414436Sstephh 			oldnptop = wcp->nptop;
12424436Sstephh 			for (np1 = oldepname, np2 = np->u.event.epname;
12434436Sstephh 			    np1 != NULL && np2 != NULL; np1 = np1->u.name.next,
12444436Sstephh 			    np2 = np2->u.name.next) {
12454436Sstephh 				if (strcmp(np1->u.name.s, np2->u.name.s) != 0)
12464436Sstephh 					break;
12474436Sstephh 				if (np1->u.name.child->t !=
12484436Sstephh 				    np2->u.name.child->t)
12494436Sstephh 					break;
12504436Sstephh 				if (np1->u.name.child->t == T_NUM &&
12514436Sstephh 				    np1->u.name.child->u.ull !=
12524436Sstephh 				    np2->u.name.child->u.ull)
12534436Sstephh 					break;
12544436Sstephh 				if (np1->u.name.child->t == T_NAME &&
12554436Sstephh 				    strcmp(np1->u.name.child->u.name.s,
12564436Sstephh 				    np2->u.name.child->u.name.s) != 0)
12574436Sstephh 					break;
12584436Sstephh 				epmatches++;
12594436Sstephh 			}
12604436Sstephh 			if (epmatches)
12614436Sstephh 				break;
12624436Sstephh 		}
12634436Sstephh 		if (epmatches && np1 == NULL && np2 == NULL) {
12644436Sstephh 			/*
12654436Sstephh 			 * complete names match, can just borrow the fields
12664436Sstephh 			 */
12674436Sstephh 			oldepname = np->u.event.epname;
12684436Sstephh 			np->u.event.epname = oldnptop->u.event.epname;
12694436Sstephh 			np->u.event.oldepname = wcp->oldepname;
12704436Sstephh 			np->u.event.ewname = wcp->ewname;
12714436Sstephh 			vmatch(infop, NULL, lnp, anp);
12724436Sstephh 			np->u.event.epname = oldepname;
12734436Sstephh 			return;
12744436Sstephh 		}
12757197Sstephh 		G.matched = 0;
12764436Sstephh 		if (epmatches) {
12774436Sstephh 			/*
12784436Sstephh 			 * just first part of names match - do wildcarding
12794436Sstephh 			 * by using existing wcp including ewname and also
12804436Sstephh 			 * copying as much of pwname as is valid, then start
12814436Sstephh 			 * vmatch_event() at start of non-matching section
12824436Sstephh 			 */
12834436Sstephh 			for (np1 = oldepname, np2 = np->u.event.epname;
12844436Sstephh 			    epmatches != 0; epmatches--) {
12854436Sstephh 				cp = np1->u.name.cp;
12864436Sstephh 				np2->u.name.cp = cp;
12874436Sstephh 				np1 = np1->u.name.next;
12884436Sstephh 				np2 = np2->u.name.next;
12894436Sstephh 			}
12904436Sstephh 			wcp->oldepname = np->u.event.epname;
12914436Sstephh 			wcp->nptop = np;
12924436Sstephh 			vmatch_event(infop, config_child(cp), np2, lnp,
12934436Sstephh 			    anp, wcp);
12944436Sstephh 			wcp->oldepname = oldepname;
12954436Sstephh 			wcp->nptop = oldnptop;
12967197Sstephh 			if (G.matched == 0) {
12977197Sstephh 				/*
12987197Sstephh 				 * This list entry is NULL. Move on to next item
12997197Sstephh 				 * in the list.
13007197Sstephh 				 */
13017197Sstephh 				vmatch(infop, NULL, lnp, anp);
13027197Sstephh 			}
13034436Sstephh 			return;
13044436Sstephh 		}
13054436Sstephh 		/*
13064436Sstephh 		 * names do not match - allocate a new wcp
13074436Sstephh 		 */
13084436Sstephh 		wcp = MALLOC(sizeof (struct wildcardinfo));
13094436Sstephh 		wcp->next = wcproot;
13104436Sstephh 		wcproot = wcp;
13114436Sstephh 		wcp->nptop = np;
13124436Sstephh 		wcp->oldepname = np->u.event.epname;
13134436Sstephh 		wcp->ewname = NULL;
1314*10146SStephen.Hanson@Sun.COM 		wcp->got_wc_hz = 0;
13154436Sstephh 
1316186Sdb35262 		vmatch_event(infop, config_child(infop->croot),
13174436Sstephh 		    np->u.event.epname, lnp, anp, wcp);
13184436Sstephh 
13194436Sstephh 		wcproot = wcp->next;
13204436Sstephh 		FREE(wcp);
13217197Sstephh 		if (G.matched == 0) {
13227197Sstephh 			/*
13237197Sstephh 			 * This list entry is NULL. Move on to next item in the
13247197Sstephh 			 * list.
13257197Sstephh 			 */
13267197Sstephh 			vmatch(infop, NULL, lnp, anp);
13277197Sstephh 		}
13280Sstevel@tonic-gate 		break;
13290Sstevel@tonic-gate 	}
13300Sstevel@tonic-gate 	case T_LIST:
13310Sstevel@tonic-gate 		ASSERT(lnp == NULL);
13324436Sstephh 		vmatch(infop, np->u.expr.right, np->u.expr.left, anp);
13330Sstevel@tonic-gate 		break;
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	case T_ARROW:
13360Sstevel@tonic-gate 		ASSERT(lnp == NULL && anp == NULL);
13377197Sstephh 		vmatch(infop, np->u.arrow.rhs, NULL, np->u.arrow.parent);
13380Sstevel@tonic-gate 		break;
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	default:
13410Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
13420Sstevel@tonic-gate 		    "vmatch: unexpected type: %s",
13430Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
13440Sstevel@tonic-gate 	}
13450Sstevel@tonic-gate }
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate static void
find_first_arrow(struct info * infop,struct node * anp)13487197Sstephh find_first_arrow(struct info *infop, struct node *anp)
13497197Sstephh {
13507197Sstephh 	if (anp->u.arrow.lhs->t == T_ARROW) {
13517197Sstephh 		anp->u.arrow.lhs->u.arrow.parent = anp;
13527197Sstephh 		find_first_arrow(infop, anp->u.arrow.lhs);
13537197Sstephh 	} else
13547197Sstephh 		vmatch(infop, anp->u.arrow.lhs, NULL, anp);
13557197Sstephh }
13567197Sstephh 
13577197Sstephh static void
cp_reset(struct node * np)13580Sstevel@tonic-gate cp_reset(struct node *np)
13590Sstevel@tonic-gate {
13600Sstevel@tonic-gate 	if (np == NULL)
13610Sstevel@tonic-gate 		return;
13620Sstevel@tonic-gate 	switch (np->t) {
13630Sstevel@tonic-gate 	case T_NAME:
13640Sstevel@tonic-gate 		np->u.name.cp = NULL;
13650Sstevel@tonic-gate 		cp_reset(np->u.name.next);
13660Sstevel@tonic-gate 		break;
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	case T_LIST:
13690Sstevel@tonic-gate 		cp_reset(np->u.expr.left);
13700Sstevel@tonic-gate 		cp_reset(np->u.expr.right);
13710Sstevel@tonic-gate 		break;
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	case T_ARROW:
13740Sstevel@tonic-gate 		cp_reset(np->u.arrow.lhs);
13750Sstevel@tonic-gate 		cp_reset(np->u.arrow.rhs);
13760Sstevel@tonic-gate 		break;
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	case T_EVENT:
13790Sstevel@tonic-gate 		cp_reset(np->u.event.epname);
13800Sstevel@tonic-gate 		break;
13810Sstevel@tonic-gate 	}
13820Sstevel@tonic-gate }
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate /*
13850Sstevel@tonic-gate  * itree_create -- apply the current config to the current parse tree
13860Sstevel@tonic-gate  *
13870Sstevel@tonic-gate  * returns a lut mapping fully-instance-qualified names to struct events.
13880Sstevel@tonic-gate  *
13890Sstevel@tonic-gate  */
13900Sstevel@tonic-gate struct lut *
itree_create(struct config * croot)13910Sstevel@tonic-gate itree_create(struct config *croot)
13920Sstevel@tonic-gate {
13930Sstevel@tonic-gate 	struct lut *retval;
13940Sstevel@tonic-gate 	struct node *propnp;
13954436Sstephh 	extern int alloc_total();
13964436Sstephh 	int init_size;
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	Ninfo.lut = NULL;
13990Sstevel@tonic-gate 	Ninfo.croot = croot;
14004436Sstephh 	init_size = alloc_total();
14014436Sstephh 	out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size);
14020Sstevel@tonic-gate 	for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
14030Sstevel@tonic-gate 		struct node *anp = propnp->u.stmt.np;
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 		ASSERTeq(anp->t, T_ARROW, ptree_nodetype2str);
14060Sstevel@tonic-gate 
14074436Sstephh 		if (!anp->u.arrow.needed)
14084436Sstephh 			continue;
14090Sstevel@tonic-gate 		Ninfo.anp = anp;
14100Sstevel@tonic-gate 		Ninfo.ex = NULL;
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 		generate_arrownp(anp);
14137197Sstephh 		anp->u.arrow.parent = NULL;
14147197Sstephh 		find_first_arrow(&Ninfo, anp);
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 		if (Ninfo.ex) {
14170Sstevel@tonic-gate 			lut_free(Ninfo.ex, iterinfo_destructor, NULL);
14180Sstevel@tonic-gate 			Ninfo.ex = NULL;
14190Sstevel@tonic-gate 		}
14200Sstevel@tonic-gate 		cp_reset(anp);
14210Sstevel@tonic-gate 	}
14220Sstevel@tonic-gate 
14234436Sstephh 	out(O_ALTFP|O_STAMP, "itree_create added %d bytes",
14244436Sstephh 	    alloc_total() - init_size);
14250Sstevel@tonic-gate 	retval = Ninfo.lut;
14260Sstevel@tonic-gate 	Ninfo.lut = NULL;
14270Sstevel@tonic-gate 	return (retval);
14280Sstevel@tonic-gate }
14290Sstevel@tonic-gate 
14304436Sstephh /*
14314436Sstephh  * initial first pass of the rules.
14324436Sstephh  * We don't use the config at all. Just check the last part of the pathname
14334436Sstephh  * in the rules. If this matches the last part of the pathname in the first
14344436Sstephh  * ereport, then set pathname to the pathname in the ereport. If not then
14354436Sstephh  * set pathname to just the last part of pathname with instance number 0.
14364436Sstephh  * Constraints are ignored and all nork values are set to 0. If after all that
14374436Sstephh  * any rules can still not be associated with the ereport, then they are set
14384436Sstephh  * to not needed in prune_propagations() and ignored in the real itree_create()
14394436Sstephh  * which follows.
14404436Sstephh  */
14414436Sstephh 
14424436Sstephh static struct event *
add_event_dummy(struct node * np,const struct ipath * ipp)14434436Sstephh add_event_dummy(struct node *np, const struct ipath *ipp)
14444436Sstephh {
14454436Sstephh 	struct event *ret;
14464436Sstephh 	struct event searchevent;	/* just used for searching */
14474436Sstephh 	extern struct ipath *ipath_dummy(struct node *, struct ipath *);
14489874SStephen.Hanson@Sun.COM 	struct ipath *ipp_un;
14499874SStephen.Hanson@Sun.COM 	extern struct ipath *ipath_for_usednames(struct node *);
14504436Sstephh 
14514436Sstephh 	searchevent.enode = np;
14524436Sstephh 	searchevent.ipp = ipath_dummy(np->u.event.epname, (struct ipath *)ipp);
14539874SStephen.Hanson@Sun.COM 	ipp_un = ipath_for_usednames(np->u.event.epname);
14544436Sstephh 	if ((ret = lut_lookup(Ninfo.lut, (void *)&searchevent,
14554436Sstephh 	    (lut_cmp)event_cmp)) != NULL)
14564436Sstephh 		return (ret);
14574436Sstephh 
14584436Sstephh 	ret = alloc_xmalloc(sizeof (*ret));
14594436Sstephh 	bzero(ret, sizeof (*ret));
14604436Sstephh 	ret->t = np->u.event.ename->u.name.t;
14614436Sstephh 	ret->enode = np;
14624436Sstephh 	ret->ipp = searchevent.ipp;
14639874SStephen.Hanson@Sun.COM 	ret->ipp_un = ipp_un;
14644436Sstephh 	Ninfo.lut = lut_add(Ninfo.lut, (void *)ret, (void *)ret,
14654436Sstephh 	    (lut_cmp)event_cmp);
14664436Sstephh 	return (ret);
14674436Sstephh }
14684436Sstephh 
14694436Sstephh /*ARGSUSED*/
14704436Sstephh struct lut *
itree_create_dummy(const char * e0class,const struct ipath * e0ipp)14714436Sstephh itree_create_dummy(const char *e0class, const struct ipath *e0ipp)
14724436Sstephh {
14734436Sstephh 	struct node *propnp;
14744436Sstephh 	struct event *frome, *toe;
14754436Sstephh 	struct bubble *frombp, *tobp;
14764436Sstephh 	struct arrow *arrowp;
14774436Sstephh 	struct node *src, *dst, *slst, *dlst, *arrownp, *oldarrownp;
14784436Sstephh 	int gen = 0;
14794436Sstephh 	extern int alloc_total();
14804436Sstephh 	int init_size;
14814436Sstephh 
14824436Sstephh 	Ninfo.lut = NULL;
14834436Sstephh 	init_size = alloc_total();
14844436Sstephh 	out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size);
14854436Sstephh 	for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
14864436Sstephh 		arrownp = propnp->u.stmt.np;
14874436Sstephh 		while (arrownp) {
14884436Sstephh 			gen++;
14894436Sstephh 			dlst = arrownp->u.arrow.rhs;
14904436Sstephh 			slst = arrownp->u.arrow.lhs;
14914436Sstephh 			oldarrownp = arrownp;
14924436Sstephh 			if (slst->t == T_ARROW) {
14934436Sstephh 				arrownp = slst;
14944436Sstephh 				slst = slst->u.arrow.rhs;
14954436Sstephh 			} else {
14964436Sstephh 				arrownp = NULL;
14974436Sstephh 			}
14984436Sstephh 			while (slst) {
14994436Sstephh 				if (slst->t == T_LIST) {
15004436Sstephh 					src = slst->u.expr.right;
15014436Sstephh 					slst = slst->u.expr.left;
15024436Sstephh 				} else {
15034436Sstephh 					src = slst;
15044436Sstephh 					slst = NULL;
15054436Sstephh 				}
15064436Sstephh 				frome = add_event_dummy(src, e0ipp);
15074436Sstephh 				frombp = itree_add_bubble(frome, B_FROM, 0, 0);
15084436Sstephh 				while (dlst) {
15094436Sstephh 					if (dlst->t == T_LIST) {
15104436Sstephh 						dst = dlst->u.expr.right;
15114436Sstephh 						dlst = dlst->u.expr.left;
15124436Sstephh 					} else {
15134436Sstephh 						dst = dlst;
15144436Sstephh 						dlst = NULL;
15154436Sstephh 					}
15164436Sstephh 					arrowp = alloc_xmalloc(
15174436Sstephh 					    sizeof (struct arrow));
15184436Sstephh 					bzero(arrowp, sizeof (struct arrow));
15194436Sstephh 					arrowp->pnode = oldarrownp;
15204436Sstephh 					toe = add_event_dummy(dst, e0ipp);
15214436Sstephh 					tobp = itree_add_bubble(toe, B_TO, 0,
15224436Sstephh 					    gen);
15234436Sstephh 					arrowp->tail = frombp;
15244436Sstephh 					arrowp->head = tobp;
15254436Sstephh 					add_arrow(frombp, arrowp);
15264436Sstephh 					add_arrow(tobp, arrowp);
15274436Sstephh 					arrow_add_within(arrowp,
15284436Sstephh 					    dst->u.event.declp->u.stmt.np->
15294436Sstephh 					    u.event.eexprlist);
15304436Sstephh 					arrow_add_within(arrowp,
15314436Sstephh 					    dst->u.event.eexprlist);
15324436Sstephh 				}
15334436Sstephh 			}
15344436Sstephh 		}
15354436Sstephh 	}
15364436Sstephh 	out(O_ALTFP|O_STAMP, "itree_create added %d bytes",
15374436Sstephh 	    alloc_total() - init_size);
15384436Sstephh 	return (Ninfo.lut);
15394436Sstephh }
15404436Sstephh 
15410Sstevel@tonic-gate void
itree_free(struct lut * lutp)15420Sstevel@tonic-gate itree_free(struct lut *lutp)
15430Sstevel@tonic-gate {
15444436Sstephh 	int init_size;
15454436Sstephh 
15464436Sstephh 	init_size = alloc_total();
15474436Sstephh 	out(O_ALTFP|O_STAMP, "start itree_free");
15480Sstevel@tonic-gate 	lut_free(lutp, itree_destructor, NULL);
15494436Sstephh 	out(O_ALTFP|O_STAMP, "itree_free freed %d bytes",
15504436Sstephh 	    init_size - alloc_total());
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate 
15531865Sdilpreet void
itree_prune(struct lut * lutp)15541865Sdilpreet itree_prune(struct lut *lutp)
15551865Sdilpreet {
15564436Sstephh 	int init_size;
15570Sstevel@tonic-gate 
15584436Sstephh 	init_size = alloc_total();
15594436Sstephh 	out(O_ALTFP|O_STAMP, "start itree_prune");
15604436Sstephh 	lut_walk(lutp, itree_pruner, NULL);
15614436Sstephh 	out(O_ALTFP|O_STAMP, "itree_prune freed %d bytes",
15624436Sstephh 	    init_size - alloc_total());
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate void
itree_pevent_brief(int flags,struct event * ep)15660Sstevel@tonic-gate itree_pevent_brief(int flags, struct event *ep)
15670Sstevel@tonic-gate {
15680Sstevel@tonic-gate 	ASSERT(ep != NULL);
15690Sstevel@tonic-gate 	ASSERT(ep->enode != NULL);
15700Sstevel@tonic-gate 	ASSERT(ep->ipp != NULL);
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 	ipath_print(flags, ep->enode->u.event.ename->u.name.s, ep->ipp);
15730Sstevel@tonic-gate }
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate /*ARGSUSED*/
15760Sstevel@tonic-gate static void
itree_pevent(struct event * lhs,struct event * ep,void * arg)15770Sstevel@tonic-gate itree_pevent(struct event *lhs, struct event *ep, void *arg)
15780Sstevel@tonic-gate {
15790Sstevel@tonic-gate 	struct plut_wlk_data propd;
15800Sstevel@tonic-gate 	struct bubble *bp;
15816277Scy152378 	int flags = (int)(intptr_t)arg;
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 	itree_pevent_brief(flags, ep);
15840Sstevel@tonic-gate 	if (ep->t == N_EREPORT)
15850Sstevel@tonic-gate 		out(flags, " (count %d)", ep->count);
15860Sstevel@tonic-gate 	else
15870Sstevel@tonic-gate 		out(flags, NULL);
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 	if (ep->props) {
15900Sstevel@tonic-gate 		propd.flags = flags;
15910Sstevel@tonic-gate 		propd.first = 1;
15920Sstevel@tonic-gate 		out(flags, "Properties:");
15930Sstevel@tonic-gate 		lut_walk(ep->props, ptree_plut, (void *)&propd);
15940Sstevel@tonic-gate 	}
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
15970Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
15980Sstevel@tonic-gate 		/* Print only TO bubbles in this loop */
15990Sstevel@tonic-gate 		if (bp->t != B_TO)
16000Sstevel@tonic-gate 			continue;
16010Sstevel@tonic-gate 		itree_pbubble(flags, bp);
16020Sstevel@tonic-gate 	}
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
16050Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
16060Sstevel@tonic-gate 		/* Print only INHIBIT bubbles in this loop */
16070Sstevel@tonic-gate 		if (bp->t != B_INHIBIT)
16080Sstevel@tonic-gate 			continue;
16090Sstevel@tonic-gate 		itree_pbubble(flags, bp);
16100Sstevel@tonic-gate 	}
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
16130Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
16140Sstevel@tonic-gate 		/* Print only FROM bubbles in this loop */
16150Sstevel@tonic-gate 		if (bp->t != B_FROM)
16160Sstevel@tonic-gate 			continue;
16170Sstevel@tonic-gate 		itree_pbubble(flags, bp);
16180Sstevel@tonic-gate 	}
16190Sstevel@tonic-gate }
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate static void
itree_pbubble(int flags,struct bubble * bp)16220Sstevel@tonic-gate itree_pbubble(int flags, struct bubble *bp)
16230Sstevel@tonic-gate {
16240Sstevel@tonic-gate 	struct constraintlist *cp;
16250Sstevel@tonic-gate 	struct arrowlist *ap;
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 	ASSERT(bp != NULL);
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate 	out(flags|O_NONL, "   ");
16300Sstevel@tonic-gate 	if (bp->mark)
16310Sstevel@tonic-gate 		out(flags|O_NONL, "*");
16320Sstevel@tonic-gate 	else
16330Sstevel@tonic-gate 		out(flags|O_NONL, " ");
16340Sstevel@tonic-gate 	if (bp->t == B_FROM)
16350Sstevel@tonic-gate 		out(flags|O_NONL, "N=%d to:", bp->nork);
16360Sstevel@tonic-gate 	else if (bp->t == B_TO)
16370Sstevel@tonic-gate 		out(flags|O_NONL, "K=%d from:", bp->nork);
16380Sstevel@tonic-gate 	else
16390Sstevel@tonic-gate 		out(flags|O_NONL, "K=%d masked from:", bp->nork);
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	if (bp->t == B_TO || bp->t == B_INHIBIT) {
16420Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
16430Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
16440Sstevel@tonic-gate 			ASSERT(ap->arrowp->head == bp);
16450Sstevel@tonic-gate 			ASSERT(ap->arrowp->tail != NULL);
16460Sstevel@tonic-gate 			ASSERT(ap->arrowp->tail->myevent != NULL);
16470Sstevel@tonic-gate 			out(flags|O_NONL, " ");
16480Sstevel@tonic-gate 			itree_pevent_brief(flags, ap->arrowp->tail->myevent);
16490Sstevel@tonic-gate 		}
16500Sstevel@tonic-gate 		out(flags, NULL);
16510Sstevel@tonic-gate 		return;
16520Sstevel@tonic-gate 	}
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	for (ap = itree_next_arrow(bp, NULL); ap;
16550Sstevel@tonic-gate 	    ap = itree_next_arrow(bp, ap)) {
16560Sstevel@tonic-gate 		ASSERT(ap->arrowp->tail == bp);
16570Sstevel@tonic-gate 		ASSERT(ap->arrowp->head != NULL);
16580Sstevel@tonic-gate 		ASSERT(ap->arrowp->head->myevent != NULL);
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 		out(flags|O_NONL, " ");
16610Sstevel@tonic-gate 		itree_pevent_brief(flags, ap->arrowp->head->myevent);
16620Sstevel@tonic-gate 
16630Sstevel@tonic-gate 		out(flags|O_NONL, " ");
16640Sstevel@tonic-gate 		ptree_timeval(flags, &ap->arrowp->mindelay);
16650Sstevel@tonic-gate 		out(flags|O_NONL, ",");
16660Sstevel@tonic-gate 		ptree_timeval(flags, &ap->arrowp->maxdelay);
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 		/* Display anything from the propogation node? */
16690Sstevel@tonic-gate 		out(O_VERB3|O_NONL, " <%s:%d>",
16700Sstevel@tonic-gate 		    ap->arrowp->pnode->file, ap->arrowp->pnode->line);
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 		if (itree_next_constraint(ap->arrowp, NULL))
16730Sstevel@tonic-gate 			out(flags|O_NONL, " {");
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 		for (cp = itree_next_constraint(ap->arrowp, NULL); cp;
16760Sstevel@tonic-gate 		    cp = itree_next_constraint(ap->arrowp, cp)) {
16770Sstevel@tonic-gate 			ptree(flags, cp->cnode, 1, 0);
16780Sstevel@tonic-gate 			if (itree_next_constraint(ap->arrowp, cp))
16790Sstevel@tonic-gate 				out(flags|O_NONL, ", ");
16800Sstevel@tonic-gate 		}
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 		if (itree_next_constraint(ap->arrowp, NULL))
16830Sstevel@tonic-gate 			out(flags|O_NONL, "}");
16840Sstevel@tonic-gate 	}
16850Sstevel@tonic-gate 	out(flags, NULL);
16860Sstevel@tonic-gate }
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate void
itree_ptree(int flags,struct lut * itp)16890Sstevel@tonic-gate itree_ptree(int flags, struct lut *itp)
16900Sstevel@tonic-gate {
16916277Scy152378 	lut_walk(itp, (lut_cb)itree_pevent, (void *)(intptr_t)flags);
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate /*ARGSUSED*/
16950Sstevel@tonic-gate static void
itree_destructor(void * left,void * right,void * arg)16960Sstevel@tonic-gate itree_destructor(void *left, void *right, void *arg)
16970Sstevel@tonic-gate {
16980Sstevel@tonic-gate 	struct event *ep = (struct event *)right;
16990Sstevel@tonic-gate 	struct bubble *nextbub, *bub;
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 	/* Free the properties */
17021865Sdilpreet 	if (ep->props)
17031865Sdilpreet 		lut_free(ep->props, instances_destructor, NULL);
17040Sstevel@tonic-gate 
17051414Scindi 	/* Free the payload properties */
17061865Sdilpreet 	if (ep->payloadprops)
17071865Sdilpreet 		lut_free(ep->payloadprops, payloadprops_destructor, NULL);
17081414Scindi 
17097197Sstephh 	/* Free the serd properties */
17107197Sstephh 	if (ep->serdprops)
17117197Sstephh 		lut_free(ep->serdprops, serdprops_destructor, NULL);
17127197Sstephh 
17130Sstevel@tonic-gate 	/* Free my bubbles */
17140Sstevel@tonic-gate 	for (bub = ep->bubbles; bub != NULL; ) {
17150Sstevel@tonic-gate 		nextbub = bub->next;
17160Sstevel@tonic-gate 		/*
17170Sstevel@tonic-gate 		 * Free arrows if they are FROM me.  Free arrowlists on
17180Sstevel@tonic-gate 		 * other types of bubbles (but not the attached arrows,
17190Sstevel@tonic-gate 		 * which will be freed when we free the originating
17200Sstevel@tonic-gate 		 * bubble.
17210Sstevel@tonic-gate 		 */
17220Sstevel@tonic-gate 		if (bub->t == B_FROM)
17230Sstevel@tonic-gate 			itree_free_arrowlists(bub, 1);
17240Sstevel@tonic-gate 		else
17250Sstevel@tonic-gate 			itree_free_arrowlists(bub, 0);
17260Sstevel@tonic-gate 		itree_free_bubble(bub);
17270Sstevel@tonic-gate 		bub = nextbub;
17280Sstevel@tonic-gate 	}
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 	if (ep->nvp != NULL)
17310Sstevel@tonic-gate 		nvlist_free(ep->nvp);
17324436Sstephh 	alloc_xfree(ep, sizeof (*ep));
17330Sstevel@tonic-gate }
17340Sstevel@tonic-gate 
17351865Sdilpreet /*ARGSUSED*/
17361865Sdilpreet static void
itree_pruner(void * left,void * right,void * arg)17371865Sdilpreet itree_pruner(void *left, void *right, void *arg)
17381865Sdilpreet {
17391865Sdilpreet 	struct event *ep = (struct event *)right;
17401865Sdilpreet 	struct bubble *nextbub, *bub;
17411865Sdilpreet 
17421865Sdilpreet 	if (ep->keep_in_tree)
17431865Sdilpreet 		return;
17441865Sdilpreet 
17451865Sdilpreet 	/* Free the properties */
17461865Sdilpreet 	lut_free(ep->props, instances_destructor, NULL);
17471865Sdilpreet 
17481865Sdilpreet 	/* Free the payload properties */
17491865Sdilpreet 	lut_free(ep->payloadprops, payloadprops_destructor, NULL);
17501865Sdilpreet 
17517197Sstephh 	/* Free the serd properties */
17527197Sstephh 	lut_free(ep->serdprops, serdprops_destructor, NULL);
17537197Sstephh 
17541865Sdilpreet 	/* Free my bubbles */
17551865Sdilpreet 	for (bub = ep->bubbles; bub != NULL; ) {
17561865Sdilpreet 		nextbub = bub->next;
17571865Sdilpreet 		itree_prune_arrowlists(bub);
17581865Sdilpreet 		itree_free_bubble(bub);
17591865Sdilpreet 		bub = nextbub;
17601865Sdilpreet 	}
17611865Sdilpreet 
17621865Sdilpreet 	if (ep->nvp != NULL)
17631865Sdilpreet 		nvlist_free(ep->nvp);
17641865Sdilpreet 	ep->props = NULL;
17651865Sdilpreet 	ep->payloadprops = NULL;
17667197Sstephh 	ep->serdprops = NULL;
17671865Sdilpreet 	ep->bubbles = NULL;
17681865Sdilpreet 	ep->nvp = NULL;
17691865Sdilpreet }
17701865Sdilpreet 
17710Sstevel@tonic-gate static void
itree_free_bubble(struct bubble * freeme)17720Sstevel@tonic-gate itree_free_bubble(struct bubble *freeme)
17730Sstevel@tonic-gate {
17744436Sstephh 	alloc_xfree(freeme, sizeof (*freeme));
17750Sstevel@tonic-gate }
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate static struct bubble *
itree_add_bubble(struct event * eventp,enum bubbletype btype,int nork,int gen)17780Sstevel@tonic-gate itree_add_bubble(struct event *eventp, enum bubbletype btype, int nork, int gen)
17790Sstevel@tonic-gate {
17800Sstevel@tonic-gate 	struct bubble *prev = NULL;
17810Sstevel@tonic-gate 	struct bubble *curr;
17820Sstevel@tonic-gate 	struct bubble *newb;
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 	/* Use existing bubbles as appropriate when possible */
17850Sstevel@tonic-gate 	for (curr = eventp->bubbles;
17860Sstevel@tonic-gate 	    curr != NULL;
17870Sstevel@tonic-gate 	    prev = curr, curr = curr->next) {
17880Sstevel@tonic-gate 		if (btype == B_TO && curr->t == B_TO) {
17890Sstevel@tonic-gate 			/* see if an existing "to" bubble works for us */
17900Sstevel@tonic-gate 			if (gen == curr->gen)
17910Sstevel@tonic-gate 				return (curr);	/* matched gen number */
17920Sstevel@tonic-gate 			else if (nork == 1 && curr->nork == 1) {
17930Sstevel@tonic-gate 				curr->gen = gen;
17940Sstevel@tonic-gate 				return (curr);	/* coalesce K==1 bubbles */
17950Sstevel@tonic-gate 			}
17960Sstevel@tonic-gate 		} else if (btype == B_FROM && curr->t == B_FROM) {
17970Sstevel@tonic-gate 			/* see if an existing "from" bubble works for us */
17980Sstevel@tonic-gate 			if ((nork == N_IS_ALL && curr->nork == N_IS_ALL) ||
17990Sstevel@tonic-gate 			    (nork == 0 && curr->nork == 0))
18000Sstevel@tonic-gate 				return (curr);
18010Sstevel@tonic-gate 		}
18020Sstevel@tonic-gate 	}
18030Sstevel@tonic-gate 
18044436Sstephh 	newb = alloc_xmalloc(sizeof (struct bubble));
18050Sstevel@tonic-gate 	newb->next = NULL;
18060Sstevel@tonic-gate 	newb->t = btype;
18070Sstevel@tonic-gate 	newb->myevent = eventp;
18080Sstevel@tonic-gate 	newb->nork = nork;
18090Sstevel@tonic-gate 	newb->mark = 0;
18100Sstevel@tonic-gate 	newb->gen = gen;
18110Sstevel@tonic-gate 	newb->arrows = NULL;
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 	if (prev == NULL)
18140Sstevel@tonic-gate 		eventp->bubbles = newb;
18150Sstevel@tonic-gate 	else
18160Sstevel@tonic-gate 		prev->next = newb;
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate 	return (newb);
18190Sstevel@tonic-gate }
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate struct bubble *
itree_next_bubble(struct event * eventp,struct bubble * last)18220Sstevel@tonic-gate itree_next_bubble(struct event *eventp, struct bubble *last)
18230Sstevel@tonic-gate {
18240Sstevel@tonic-gate 	struct bubble *next;
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 	for (;;) {
18270Sstevel@tonic-gate 		if (last != NULL)
18280Sstevel@tonic-gate 			next = last->next;
18290Sstevel@tonic-gate 		else
18300Sstevel@tonic-gate 			next = eventp->bubbles;
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate 		if (next == NULL || next->arrows != NULL)
18330Sstevel@tonic-gate 			return (next);
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 		/* bubble was empty, skip it */
18360Sstevel@tonic-gate 		last = next;
18370Sstevel@tonic-gate 	}
18380Sstevel@tonic-gate }
18390Sstevel@tonic-gate 
18400Sstevel@tonic-gate static void
add_arrow(struct bubble * bp,struct arrow * ap)18410Sstevel@tonic-gate add_arrow(struct bubble *bp, struct arrow *ap)
18420Sstevel@tonic-gate {
18430Sstevel@tonic-gate 	struct arrowlist *prev = NULL;
18440Sstevel@tonic-gate 	struct arrowlist *curr;
18450Sstevel@tonic-gate 	struct arrowlist *newal;
18460Sstevel@tonic-gate 
18474436Sstephh 	newal = alloc_xmalloc(sizeof (struct arrowlist));
18480Sstevel@tonic-gate 	bzero(newal, sizeof (struct arrowlist));
18490Sstevel@tonic-gate 	newal->arrowp = ap;
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 	curr = itree_next_arrow(bp, NULL);
18520Sstevel@tonic-gate 	while (curr != NULL) {
18530Sstevel@tonic-gate 		prev = curr;
18540Sstevel@tonic-gate 		curr = itree_next_arrow(bp, curr);
18550Sstevel@tonic-gate 	}
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 	if (prev == NULL)
18580Sstevel@tonic-gate 		bp->arrows = newal;
18590Sstevel@tonic-gate 	else
18600Sstevel@tonic-gate 		prev->next = newal;
18610Sstevel@tonic-gate }
18620Sstevel@tonic-gate 
18630Sstevel@tonic-gate static struct arrow *
itree_add_arrow(struct node * apnode,struct node * fromevent,struct node * toevent,struct lut * ex)18644436Sstephh itree_add_arrow(struct node *apnode, struct node *fromevent,
18654436Sstephh     struct node *toevent, struct lut *ex)
18660Sstevel@tonic-gate {
18670Sstevel@tonic-gate 	struct arrow *newa;
18680Sstevel@tonic-gate 
18694436Sstephh 	newa = alloc_xmalloc(sizeof (struct arrow));
18701414Scindi 	bzero(newa, sizeof (struct arrow));
18710Sstevel@tonic-gate 	newa->pnode = apnode;
18720Sstevel@tonic-gate 	newa->constraints = NULL;
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate 	/*
18750Sstevel@tonic-gate 	 *  Set default delays, then try to re-set them from
18760Sstevel@tonic-gate 	 *  any within() constraints.
18770Sstevel@tonic-gate 	 */
18780Sstevel@tonic-gate 	newa->mindelay = newa->maxdelay = 0ULL;
18790Sstevel@tonic-gate 	if (itree_set_arrow_traits(newa, fromevent, toevent, ex) == 0) {
18804436Sstephh 		alloc_xfree(newa, sizeof (struct arrow));
18810Sstevel@tonic-gate 		return (NULL);
18820Sstevel@tonic-gate 	}
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 	return (newa);
18850Sstevel@tonic-gate }
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate /* returns false if traits show that arrow should not be added after all */
18880Sstevel@tonic-gate static int
itree_set_arrow_traits(struct arrow * ap,struct node * fromev,struct node * toev,struct lut * ex)18890Sstevel@tonic-gate itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
18900Sstevel@tonic-gate     struct node *toev, struct lut *ex)
18910Sstevel@tonic-gate {
18924436Sstephh 	struct node *events[] = { NULL, NULL, NULL };
18930Sstevel@tonic-gate 	struct node *newc = NULL;
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	ASSERTeq(fromev->t, T_EVENT, ptree_nodetype2str);
18960Sstevel@tonic-gate 	ASSERTeq(toev->t, T_EVENT, ptree_nodetype2str);
18970Sstevel@tonic-gate 
18980Sstevel@tonic-gate 	/*
18990Sstevel@tonic-gate 	 * search for the within values first on the declaration of
19000Sstevel@tonic-gate 	 * the destination event, and then on the prop.  this allows
19010Sstevel@tonic-gate 	 * one to specify a "default" within by putting it on the
19020Sstevel@tonic-gate 	 * declaration,  but then allow overriding on the prop statement.
19030Sstevel@tonic-gate 	 */
19040Sstevel@tonic-gate 	arrow_add_within(ap, toev->u.event.declp->u.stmt.np->u.event.eexprlist);
19050Sstevel@tonic-gate 	arrow_add_within(ap, toev->u.event.eexprlist);
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 	/*
19080Sstevel@tonic-gate 	 * handle any global constraints inherited from the
19090Sstevel@tonic-gate 	 * "fromev" event's declaration
19100Sstevel@tonic-gate 	 */
19110Sstevel@tonic-gate 	ASSERT(fromev->u.event.declp != NULL);
19120Sstevel@tonic-gate 	ASSERT(fromev->u.event.declp->u.stmt.np != NULL);
19130Sstevel@tonic-gate 
19140Sstevel@tonic-gate #ifdef	notdef
19150Sstevel@tonic-gate 	/* XXX not quite ready to evaluate constraints from decls yet */
19160Sstevel@tonic-gate 	if (fromev->u.event.declp->u.stmt.np->u.event.eexprlist)
19170Sstevel@tonic-gate 		(void) itree_add_constraint(ap,
19180Sstevel@tonic-gate 		    fromev->u.event.declp->u.stmt.np->u.event.eexprlist);
19190Sstevel@tonic-gate #endif	/* notdef */
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 	/* handle constraints on the from event in the prop statement */
19224436Sstephh 	events[0] = fromev;
19234436Sstephh 	events[1] = toev;
19244436Sstephh 	if (eval_potential(fromev->u.event.eexprlist, ex, events, &newc,
19252318Sstephh 	    Ninfo.croot) == 0)
19260Sstevel@tonic-gate 		return (0);		/* constraint disallows arrow */
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 	/*
19290Sstevel@tonic-gate 	 * handle any global constraints inherited from the
19300Sstevel@tonic-gate 	 * "toev" event's declaration
19310Sstevel@tonic-gate 	 */
19320Sstevel@tonic-gate 	ASSERT(toev->u.event.declp != NULL);
19330Sstevel@tonic-gate 	ASSERT(toev->u.event.declp->u.stmt.np != NULL);
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate #ifdef	notdef
19360Sstevel@tonic-gate 	/* XXX not quite ready to evaluate constraints from decls yet */
19370Sstevel@tonic-gate 	if (toev->u.event.declp->u.stmt.np->u.event.eexprlist)
19380Sstevel@tonic-gate 		(void) itree_add_constraint(ap,
19390Sstevel@tonic-gate 		    toev->u.event.declp->u.stmt.np->u.event.eexprlist);
19400Sstevel@tonic-gate #endif	/* notdef */
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 	/* handle constraints on the to event in the prop statement */
19434436Sstephh 	events[0] = toev;
19444436Sstephh 	events[1] = fromev;
19454436Sstephh 	if (eval_potential(toev->u.event.eexprlist, ex, events, &newc,
19462318Sstephh 	    Ninfo.croot) == 0) {
19471865Sdilpreet 		if (newc != NULL)
19481865Sdilpreet 			tree_free(newc);
19490Sstevel@tonic-gate 		return (0);		/* constraint disallows arrow */
19501865Sdilpreet 	}
19510Sstevel@tonic-gate 
19520Sstevel@tonic-gate 	/* if we came up with any deferred constraints, add them to arrow */
19534436Sstephh 	if (newc != NULL) {
19544436Sstephh 		out(O_ALTFP|O_VERB3, "(deferred constraints)");
19551414Scindi 		(void) itree_add_constraint(ap, iexpr(newc));
19564436Sstephh 	}
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate 	return (1);	/* constraints allow arrow */
19590Sstevel@tonic-gate }
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate /*
19620Sstevel@tonic-gate  * Set within() constraint.  If the constraint were set multiple times,
19630Sstevel@tonic-gate  * the last one would "win".
19640Sstevel@tonic-gate  */
19650Sstevel@tonic-gate static void
arrow_add_within(struct arrow * ap,struct node * xpr)19660Sstevel@tonic-gate arrow_add_within(struct arrow *ap, struct node *xpr)
19670Sstevel@tonic-gate {
19680Sstevel@tonic-gate 	struct node *arglist;
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate 	/* end of expressions list */
19710Sstevel@tonic-gate 	if (xpr == NULL)
19720Sstevel@tonic-gate 		return;
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	switch (xpr->t) {
19750Sstevel@tonic-gate 	case T_LIST:
19760Sstevel@tonic-gate 		arrow_add_within(ap, xpr->u.expr.left);
19770Sstevel@tonic-gate 		arrow_add_within(ap, xpr->u.expr.right);
19780Sstevel@tonic-gate 		return;
19790Sstevel@tonic-gate 	case T_FUNC:
19800Sstevel@tonic-gate 		if (xpr->u.func.s != L_within)
19810Sstevel@tonic-gate 			return;
19820Sstevel@tonic-gate 		arglist = xpr->u.func.arglist;
19830Sstevel@tonic-gate 		switch (arglist->t) {
19840Sstevel@tonic-gate 		case T_TIMEVAL:
19850Sstevel@tonic-gate 			ap->mindelay = 0;
19860Sstevel@tonic-gate 			ap->maxdelay = arglist->u.ull;
19870Sstevel@tonic-gate 			break;
19880Sstevel@tonic-gate 		case T_NAME:
19890Sstevel@tonic-gate 			ASSERT(arglist->u.name.s == L_infinity);
19900Sstevel@tonic-gate 			ap->mindelay = 0;
19910Sstevel@tonic-gate 			ap->maxdelay = TIMEVAL_EVENTUALLY;
19920Sstevel@tonic-gate 			break;
19930Sstevel@tonic-gate 		case T_LIST:
19940Sstevel@tonic-gate 			ASSERT(arglist->u.expr.left->t == T_TIMEVAL);
19950Sstevel@tonic-gate 			ap->mindelay = arglist->u.expr.left->u.ull;
19960Sstevel@tonic-gate 			switch (arglist->u.expr.right->t) {
19970Sstevel@tonic-gate 			case T_TIMEVAL:
19980Sstevel@tonic-gate 				ap->maxdelay = arglist->u.ull;
19990Sstevel@tonic-gate 				break;
20000Sstevel@tonic-gate 			case T_NAME:
20010Sstevel@tonic-gate 				ASSERT(arglist->u.expr.right->u.name.s ==
20020Sstevel@tonic-gate 				    L_infinity);
20030Sstevel@tonic-gate 				ap->maxdelay = TIMEVAL_EVENTUALLY;
20040Sstevel@tonic-gate 				break;
20050Sstevel@tonic-gate 			default:
20060Sstevel@tonic-gate 				out(O_DIE, "within: unexpected 2nd arg type");
20070Sstevel@tonic-gate 			}
20080Sstevel@tonic-gate 			break;
20090Sstevel@tonic-gate 		default:
20100Sstevel@tonic-gate 			out(O_DIE, "within: unexpected 1st arg type");
20110Sstevel@tonic-gate 		}
20120Sstevel@tonic-gate 		break;
20130Sstevel@tonic-gate 	default:
20140Sstevel@tonic-gate 		return;
20150Sstevel@tonic-gate 	}
20160Sstevel@tonic-gate }
20170Sstevel@tonic-gate 
20180Sstevel@tonic-gate static void
itree_free_arrowlists(struct bubble * bubp,int arrows_too)20190Sstevel@tonic-gate itree_free_arrowlists(struct bubble *bubp, int arrows_too)
20200Sstevel@tonic-gate {
20210Sstevel@tonic-gate 	struct arrowlist *al, *nal;
20220Sstevel@tonic-gate 
20230Sstevel@tonic-gate 	al = bubp->arrows;
20240Sstevel@tonic-gate 	while (al != NULL) {
20250Sstevel@tonic-gate 		nal = al->next;
20260Sstevel@tonic-gate 		if (arrows_too) {
20270Sstevel@tonic-gate 			itree_free_constraints(al->arrowp);
20284436Sstephh 			alloc_xfree(al->arrowp, sizeof (struct arrow));
20290Sstevel@tonic-gate 		}
20304436Sstephh 		alloc_xfree(al, sizeof (*al));
20310Sstevel@tonic-gate 		al = nal;
20320Sstevel@tonic-gate 	}
20330Sstevel@tonic-gate }
20340Sstevel@tonic-gate 
20351865Sdilpreet static void
itree_delete_arrow(struct bubble * bubp,struct arrow * arrow)20361865Sdilpreet itree_delete_arrow(struct bubble *bubp, struct arrow *arrow)
20371865Sdilpreet {
20381865Sdilpreet 	struct arrowlist *al, *oal;
20391865Sdilpreet 
20401865Sdilpreet 	al = bubp->arrows;
20411865Sdilpreet 	if (al->arrowp == arrow) {
20421865Sdilpreet 		bubp->arrows = al->next;
20434436Sstephh 		alloc_xfree(al, sizeof (*al));
20441865Sdilpreet 		return;
20451865Sdilpreet 	}
20461865Sdilpreet 	while (al != NULL) {
20471865Sdilpreet 		oal = al;
20481865Sdilpreet 		al = al->next;
20491865Sdilpreet 		ASSERT(al != NULL);
20501865Sdilpreet 		if (al->arrowp == arrow) {
20511865Sdilpreet 			oal->next = al->next;
20524436Sstephh 			alloc_xfree(al, sizeof (*al));
20531865Sdilpreet 			return;
20541865Sdilpreet 		}
20551865Sdilpreet 	}
20561865Sdilpreet }
20571865Sdilpreet 
20581865Sdilpreet static void
itree_prune_arrowlists(struct bubble * bubp)20591865Sdilpreet itree_prune_arrowlists(struct bubble *bubp)
20601865Sdilpreet {
20611865Sdilpreet 	struct arrowlist *al, *nal;
20621865Sdilpreet 
20631865Sdilpreet 	al = bubp->arrows;
20641865Sdilpreet 	while (al != NULL) {
20651865Sdilpreet 		nal = al->next;
20661865Sdilpreet 		if (bubp->t == B_FROM)
20671865Sdilpreet 			itree_delete_arrow(al->arrowp->head, al->arrowp);
20681865Sdilpreet 		else
20691865Sdilpreet 			itree_delete_arrow(al->arrowp->tail, al->arrowp);
20701865Sdilpreet 		itree_free_constraints(al->arrowp);
20714436Sstephh 		alloc_xfree(al->arrowp, sizeof (struct arrow));
20724436Sstephh 		alloc_xfree(al, sizeof (*al));
20731865Sdilpreet 		al = nal;
20741865Sdilpreet 	}
20751865Sdilpreet }
20761865Sdilpreet 
20770Sstevel@tonic-gate struct arrowlist *
itree_next_arrow(struct bubble * bubble,struct arrowlist * last)20780Sstevel@tonic-gate itree_next_arrow(struct bubble *bubble, struct arrowlist *last)
20790Sstevel@tonic-gate {
20800Sstevel@tonic-gate 	struct arrowlist *next;
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate 	if (last != NULL)
20830Sstevel@tonic-gate 		next = last->next;
20840Sstevel@tonic-gate 	else
20850Sstevel@tonic-gate 		next = bubble->arrows;
20860Sstevel@tonic-gate 	return (next);
20870Sstevel@tonic-gate }
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate static struct constraintlist *
itree_add_constraint(struct arrow * arrowp,struct node * c)20900Sstevel@tonic-gate itree_add_constraint(struct arrow *arrowp, struct node *c)
20910Sstevel@tonic-gate {
20920Sstevel@tonic-gate 	struct constraintlist *prev = NULL;
20930Sstevel@tonic-gate 	struct constraintlist *curr;
20940Sstevel@tonic-gate 	struct constraintlist *newc;
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate 	for (curr = arrowp->constraints;
20970Sstevel@tonic-gate 	    curr != NULL;
20984436Sstephh 	    prev = curr, curr = curr->next)
20994436Sstephh 		;
21000Sstevel@tonic-gate 
21014436Sstephh 	newc = alloc_xmalloc(sizeof (struct constraintlist));
21020Sstevel@tonic-gate 	newc->next = NULL;
21030Sstevel@tonic-gate 	newc->cnode = c;
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate 	if (prev == NULL)
21060Sstevel@tonic-gate 		arrowp->constraints = newc;
21070Sstevel@tonic-gate 	else
21080Sstevel@tonic-gate 		prev->next = newc;
21090Sstevel@tonic-gate 
21100Sstevel@tonic-gate 	return (newc);
21110Sstevel@tonic-gate }
21120Sstevel@tonic-gate 
21130Sstevel@tonic-gate struct constraintlist *
itree_next_constraint(struct arrow * arrowp,struct constraintlist * last)21140Sstevel@tonic-gate itree_next_constraint(struct arrow *arrowp, struct constraintlist *last)
21150Sstevel@tonic-gate {
21160Sstevel@tonic-gate 	struct constraintlist *next;
21170Sstevel@tonic-gate 
21180Sstevel@tonic-gate 	if (last != NULL)
21190Sstevel@tonic-gate 		next = last->next;
21200Sstevel@tonic-gate 	else
21210Sstevel@tonic-gate 		next = arrowp->constraints;
21220Sstevel@tonic-gate 	return (next);
21230Sstevel@tonic-gate }
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate static void
itree_free_constraints(struct arrow * ap)21260Sstevel@tonic-gate itree_free_constraints(struct arrow *ap)
21270Sstevel@tonic-gate {
21280Sstevel@tonic-gate 	struct constraintlist *cl, *ncl;
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate 	cl = ap->constraints;
21310Sstevel@tonic-gate 	while (cl != NULL) {
21320Sstevel@tonic-gate 		ncl = cl->next;
21330Sstevel@tonic-gate 		ASSERT(cl->cnode != NULL);
21341414Scindi 		if (!iexpr_cached(cl->cnode))
21351414Scindi 			tree_free(cl->cnode);
21361865Sdilpreet 		else
21371865Sdilpreet 			iexpr_free(cl->cnode);
21384436Sstephh 		alloc_xfree(cl, sizeof (*cl));
21390Sstevel@tonic-gate 		cl = ncl;
21400Sstevel@tonic-gate 	}
21410Sstevel@tonic-gate }
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate const char *
itree_bubbletype2str(enum bubbletype t)21440Sstevel@tonic-gate itree_bubbletype2str(enum bubbletype t)
21450Sstevel@tonic-gate {
21460Sstevel@tonic-gate 	static char buf[100];
21470Sstevel@tonic-gate 
21480Sstevel@tonic-gate 	switch (t) {
21490Sstevel@tonic-gate 	case B_FROM:	return L_from;
21500Sstevel@tonic-gate 	case B_TO:	return L_to;
21510Sstevel@tonic-gate 	case B_INHIBIT:	return L_inhibit;
21520Sstevel@tonic-gate 	default:
21530Sstevel@tonic-gate 		(void) sprintf(buf, "[unexpected bubbletype: %d]", t);
21540Sstevel@tonic-gate 		return (buf);
21550Sstevel@tonic-gate 	}
21560Sstevel@tonic-gate }
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate /*
21590Sstevel@tonic-gate  * itree_fini -- clean up any half-built itrees
21600Sstevel@tonic-gate  */
21610Sstevel@tonic-gate void
itree_fini(void)21620Sstevel@tonic-gate itree_fini(void)
21630Sstevel@tonic-gate {
21640Sstevel@tonic-gate 	if (Ninfo.lut != NULL) {
21650Sstevel@tonic-gate 		itree_free(Ninfo.lut);
21660Sstevel@tonic-gate 		Ninfo.lut = NULL;
21670Sstevel@tonic-gate 	}
21680Sstevel@tonic-gate 	if (Ninfo.ex) {
21690Sstevel@tonic-gate 		lut_free(Ninfo.ex, iterinfo_destructor, NULL);
21700Sstevel@tonic-gate 		Ninfo.ex = NULL;
21710Sstevel@tonic-gate 	}
21720Sstevel@tonic-gate }
2173