17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
580ab886dSwesolows  * Common Development and Distribution License (the "License").
680ab886dSwesolows  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2180ab886dSwesolows 
227c478bd9Sstevel@tonic-gate /*
236e1fa242SStephen Hanson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * itree.c -- instance tree creation and manipulation
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * this module provides the instance tree
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <ctype.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <strings.h>
357c478bd9Sstevel@tonic-gate #include "alloc.h"
367c478bd9Sstevel@tonic-gate #include "out.h"
377c478bd9Sstevel@tonic-gate #include "stable.h"
387c478bd9Sstevel@tonic-gate #include "literals.h"
397c478bd9Sstevel@tonic-gate #include "lut.h"
407c478bd9Sstevel@tonic-gate #include "tree.h"
417c478bd9Sstevel@tonic-gate #include "ptree.h"
427c478bd9Sstevel@tonic-gate #include "itree.h"
437c478bd9Sstevel@tonic-gate #include "ipath.h"
447aec1d6eScindi #include "iexpr.h"
457c478bd9Sstevel@tonic-gate #include "eval.h"
467c478bd9Sstevel@tonic-gate #include "config.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  * struct info contains the state we keep when expanding a prop statement
507c478bd9Sstevel@tonic-gate  * as part of constructing the instance tree.  state kept in struct info
517c478bd9Sstevel@tonic-gate  * is the non-recursive stuff -- the stuff that doesn't need to be on
527c478bd9Sstevel@tonic-gate  * the stack.  the rest of the state that is passed between all the
537c478bd9Sstevel@tonic-gate  * mutually recursive functions, is required to be on the stack since
547c478bd9Sstevel@tonic-gate  * we need to backtrack and recurse as we do the instance tree construction.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate struct info {
577c478bd9Sstevel@tonic-gate 	struct lut *lut;
587c478bd9Sstevel@tonic-gate 	struct node *anp;	/* arrow np */
597c478bd9Sstevel@tonic-gate 	struct lut *ex;		/* dictionary of explicit iterators */
607c478bd9Sstevel@tonic-gate 	struct config *croot;
617c478bd9Sstevel@tonic-gate } Ninfo;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * struct wildcardinfo is used to track wildcarded portions of paths.
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  * for example, if the epname of an event is "c/d" and the path "a/b/c/d"
677c478bd9Sstevel@tonic-gate  * exists, the wildcard path ewname is filled in with the path "a/b".  when
687c478bd9Sstevel@tonic-gate  * matching is done, epname is temporarily replaced with the concatenation
69b5016cbbSstephh  * of ewname and epname.
707c478bd9Sstevel@tonic-gate  *
717c478bd9Sstevel@tonic-gate  * a linked list of these structs is used to track the expansion of each
727c478bd9Sstevel@tonic-gate  * event node as it is processed in vmatch() --> vmatch_event() calls.
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate struct wildcardinfo {
757c478bd9Sstevel@tonic-gate 	struct node *nptop;		/* event node fed to vmatch */
767c478bd9Sstevel@tonic-gate 	struct node *oldepname;		/* epname without the wildcard part */
777c478bd9Sstevel@tonic-gate 	struct node *ewname;		/* wildcard path */
78*26733bfeSStephen Hanson 	int got_wc_hz;
797c478bd9Sstevel@tonic-gate 	struct wildcardinfo *next;
807c478bd9Sstevel@tonic-gate };
817c478bd9Sstevel@tonic-gate 
82b5016cbbSstephh static struct wildcardinfo *wcproot = NULL;
83b5016cbbSstephh 
84b5016cbbSstephh static void vmatch(struct info *infop, struct node *np, struct node *lnp,
85b5016cbbSstephh     struct node *anp);
867c478bd9Sstevel@tonic-gate static void hmatch(struct info *infop, struct node *np, struct node *nextnp);
87*26733bfeSStephen Hanson static void hmatch_event(struct info *infop, struct node *eventnp,
88*26733bfeSStephen Hanson     struct node *epname, struct config *ncp, struct node *nextnp, int rematch);
897c478bd9Sstevel@tonic-gate static void itree_pbubble(int flags, struct bubble *bp);
9000d0963fSdilpreet static void itree_pruner(void *left, void *right, void *arg);
917c478bd9Sstevel@tonic-gate static void itree_destructor(void *left, void *right, void *arg);
927c478bd9Sstevel@tonic-gate static int itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
937c478bd9Sstevel@tonic-gate     struct node *toev, struct lut *ex);
947c478bd9Sstevel@tonic-gate static void itree_free_arrowlists(struct bubble *bubp, int arrows_too);
9500d0963fSdilpreet static void itree_prune_arrowlists(struct bubble *bubp);
967c478bd9Sstevel@tonic-gate static void arrow_add_within(struct arrow *ap, struct node *xpr);
97b5016cbbSstephh static struct arrow *itree_add_arrow(struct node *apnode,
98b5016cbbSstephh     struct node *fromevent, struct node *toevent, struct lut *ex);
99b5016cbbSstephh static struct event *find_or_add_event(struct info *infop, struct node *np);
100b5016cbbSstephh static void add_arrow(struct bubble *bp, struct arrow *ap);
1017c478bd9Sstevel@tonic-gate static struct constraintlist *itree_add_constraint(struct arrow *arrowp,
1027c478bd9Sstevel@tonic-gate     struct node *c);
1037c478bd9Sstevel@tonic-gate static struct bubble *itree_add_bubble(struct event *eventp,
1047c478bd9Sstevel@tonic-gate     enum bubbletype btype, int nork, int gen);
1057c478bd9Sstevel@tonic-gate static void itree_free_bubble(struct bubble *freeme);
1067c478bd9Sstevel@tonic-gate static void itree_free_constraints(struct arrow *ap);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /*
1097c478bd9Sstevel@tonic-gate  * the following struct contains the state we build up during
1107c478bd9Sstevel@tonic-gate  * vertical and horizontal expansion so that generate()
1117c478bd9Sstevel@tonic-gate  * has everything it needs to construct the appropriate arrows.
1127c478bd9Sstevel@tonic-gate  * after setting up the state by calling:
1137c478bd9Sstevel@tonic-gate  *	generate_arrownp()
1147c478bd9Sstevel@tonic-gate  *	generate_nork()
1157c478bd9Sstevel@tonic-gate  *	generate_new()
1167c478bd9Sstevel@tonic-gate  *	generate_from()
1177c478bd9Sstevel@tonic-gate  *	generate_to()
1187c478bd9Sstevel@tonic-gate  * the actual arrow generation is done by calling:
1197c478bd9Sstevel@tonic-gate  *	generate()
1207c478bd9Sstevel@tonic-gate  */
1217c478bd9Sstevel@tonic-gate static struct {
1227c478bd9Sstevel@tonic-gate 	int generation;		/* generation number of arrow set */
123b7d3956bSstephh 	int matched;		/* number of matches */
1247c478bd9Sstevel@tonic-gate 	struct node *arrownp;	/* top-level parse tree for arrow */
1257c478bd9Sstevel@tonic-gate 	int n;			/* n value associated with arrow */
1267c478bd9Sstevel@tonic-gate 	int k;			/* k value associated with arrow */
1277c478bd9Sstevel@tonic-gate 	struct node *fromnp;	/* left-hand-side event in parse tree */
1287c478bd9Sstevel@tonic-gate 	struct node *tonp;	/* right-hand-side event in parse tree */
1297c478bd9Sstevel@tonic-gate 	struct event *frome;	/* left-hand-side event in instance tree */
1307c478bd9Sstevel@tonic-gate 	struct event *toe;	/* right-hand-side event in instance tree */
1317c478bd9Sstevel@tonic-gate 	struct bubble *frombp;	/* bubble arrow comes from */
1327c478bd9Sstevel@tonic-gate 	struct bubble *tobp;	/* bubble arrow goes to */
1337c478bd9Sstevel@tonic-gate } G;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate static void
generate_arrownp(struct node * arrownp)1367c478bd9Sstevel@tonic-gate generate_arrownp(struct node *arrownp)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate 	G.arrownp = arrownp;
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate static void
generate_nork(int n,int k)1427c478bd9Sstevel@tonic-gate generate_nork(int n, int k)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	G.n = n;
1457c478bd9Sstevel@tonic-gate 	G.k = k;
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate static void
generate_new(void)1497c478bd9Sstevel@tonic-gate generate_new(void)
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate 	G.generation++;
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate static void
generate_from(struct node * fromeventnp)155b5016cbbSstephh generate_from(struct node *fromeventnp)
1567c478bd9Sstevel@tonic-gate {
157b5016cbbSstephh 	G.frombp = NULL;
1587c478bd9Sstevel@tonic-gate 	G.fromnp = fromeventnp;
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate static void
generate_to(struct node * toeventnp)162b5016cbbSstephh generate_to(struct node *toeventnp)
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate 	G.tonp = toeventnp;
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate static void
generate(struct info * infop)168b5016cbbSstephh generate(struct info *infop)
1697c478bd9Sstevel@tonic-gate {
170b5016cbbSstephh 	struct arrow *arrowp;
171b5016cbbSstephh 
1727c478bd9Sstevel@tonic-gate 	ASSERT(G.arrownp != NULL);
1737c478bd9Sstevel@tonic-gate 	ASSERT(G.fromnp != NULL);
1747c478bd9Sstevel@tonic-gate 	ASSERT(G.tonp != NULL);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL, "        Arrow \"");
1777c478bd9Sstevel@tonic-gate 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp);
1787c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL, "\" -> \"");
1797c478bd9Sstevel@tonic-gate 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp);
180b5016cbbSstephh 	out(O_ALTFP|O_VERB3|O_NONL, "\" ");
1817c478bd9Sstevel@tonic-gate 
182b5016cbbSstephh 	arrowp = itree_add_arrow(G.arrownp, G.fromnp, G.tonp, infop->ex);
183b5016cbbSstephh 	if (arrowp == NULL) {
184b5016cbbSstephh 		out(O_ALTFP|O_VERB3, "(prevented by constraints)");
1857c478bd9Sstevel@tonic-gate 	} else {
186b5016cbbSstephh 		out(O_ALTFP|O_VERB3, "");
187b5016cbbSstephh 		if (!G.frombp) {
188b5016cbbSstephh 			G.frome = find_or_add_event(infop, G.fromnp);
189b5016cbbSstephh 			G.frombp = itree_add_bubble(G.frome, B_FROM, G.n, 0);
190b5016cbbSstephh 		}
191b5016cbbSstephh 		G.toe = find_or_add_event(infop, G.tonp);
192b5016cbbSstephh 		G.tobp = itree_add_bubble(G.toe, B_TO, G.k, G.generation);
193b5016cbbSstephh 		arrowp->tail = G.frombp;
194b5016cbbSstephh 		arrowp->head = G.tobp;
195b5016cbbSstephh 		add_arrow(G.frombp, arrowp);
196b5016cbbSstephh 		add_arrow(G.tobp, arrowp);
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate enum childnode_action {
2017c478bd9Sstevel@tonic-gate 	CN_NONE,
2027c478bd9Sstevel@tonic-gate 	CN_DUP
2037c478bd9Sstevel@tonic-gate };
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate static struct node *
tname_dup(struct node * namep,enum childnode_action act)2067c478bd9Sstevel@tonic-gate tname_dup(struct node *namep, enum childnode_action act)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	struct node *retp = NULL;
2097c478bd9Sstevel@tonic-gate 	const char *file;
2107c478bd9Sstevel@tonic-gate 	int line;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if (namep == NULL)
2137c478bd9Sstevel@tonic-gate 		return (NULL);
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	file = namep->file;
2167c478bd9Sstevel@tonic-gate 	line = namep->line;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	for (; namep != NULL; namep = namep->u.name.next) {
2197c478bd9Sstevel@tonic-gate 		struct node *newnp = newnode(T_NAME, file, line);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 		newnp->u.name.t = namep->u.name.t;
2227c478bd9Sstevel@tonic-gate 		newnp->u.name.s = namep->u.name.s;
2237c478bd9Sstevel@tonic-gate 		newnp->u.name.last = newnp;
2247c478bd9Sstevel@tonic-gate 		newnp->u.name.it = namep->u.name.it;
2257c478bd9Sstevel@tonic-gate 		newnp->u.name.cp = namep->u.name.cp;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 		if (act == CN_DUP) {
2287c478bd9Sstevel@tonic-gate 			struct node *npc;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 			npc = namep->u.name.child;
2317c478bd9Sstevel@tonic-gate 			if (npc != NULL) {
2327c478bd9Sstevel@tonic-gate 				switch (npc->t) {
2337c478bd9Sstevel@tonic-gate 				case T_NUM:
2347c478bd9Sstevel@tonic-gate 					newnp->u.name.child =
2357c478bd9Sstevel@tonic-gate 					    newnode(T_NUM, file, line);
2367c478bd9Sstevel@tonic-gate 					newnp->u.name.child->u.ull =
2377c478bd9Sstevel@tonic-gate 					    npc->u.ull;
2387c478bd9Sstevel@tonic-gate 					break;
2397c478bd9Sstevel@tonic-gate 				case T_NAME:
2407c478bd9Sstevel@tonic-gate 					newnp->u.name.child =
2417c478bd9Sstevel@tonic-gate 					    tree_name(npc->u.name.s,
242b5016cbbSstephh 					    npc->u.name.it, file, line);
2437c478bd9Sstevel@tonic-gate 					break;
2447c478bd9Sstevel@tonic-gate 				default:
2457c478bd9Sstevel@tonic-gate 					out(O_DIE, "tname_dup: "
2467c478bd9Sstevel@tonic-gate 					    "invalid child type %s",
2477c478bd9Sstevel@tonic-gate 					    ptree_nodetype2str(npc->t));
2487c478bd9Sstevel@tonic-gate 				}
2497c478bd9Sstevel@tonic-gate 			}
2507c478bd9Sstevel@tonic-gate 		}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 		if (retp == NULL) {
2537c478bd9Sstevel@tonic-gate 			retp = newnp;
2547c478bd9Sstevel@tonic-gate 		} else {
2557c478bd9Sstevel@tonic-gate 			retp->u.name.last->u.name.next = newnp;
2567c478bd9Sstevel@tonic-gate 			retp->u.name.last = newnp;
2577c478bd9Sstevel@tonic-gate 		}
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	return (retp);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate struct prop_wlk_data {
2647c478bd9Sstevel@tonic-gate 	struct lut *props;
2657c478bd9Sstevel@tonic-gate 	struct node *epname;
2667c478bd9Sstevel@tonic-gate };
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate static struct lut *props2instance(struct node *, struct node *);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate /*
2717c478bd9Sstevel@tonic-gate  * let oldepname be a subset of epname.  return the subsection of epname
2727c478bd9Sstevel@tonic-gate  * that ends with oldepname.  make each component in the path explicitly
2737c478bd9Sstevel@tonic-gate  * instanced (i.e., with a T_NUM child).
2747c478bd9Sstevel@tonic-gate  */
2757c478bd9Sstevel@tonic-gate static struct node *
tname_dup_to_epname(struct node * oldepname,struct node * epname)2767c478bd9Sstevel@tonic-gate tname_dup_to_epname(struct node *oldepname, struct node *epname)
2777c478bd9Sstevel@tonic-gate {
2787c478bd9Sstevel@tonic-gate 	struct node *npref, *npend, *np1, *np2;
2797c478bd9Sstevel@tonic-gate 	struct node *ret = NULL;
2807c478bd9Sstevel@tonic-gate 	int foundmatch = 0;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	if (epname == NULL)
2837c478bd9Sstevel@tonic-gate 		return (NULL);
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	/*
2867c478bd9Sstevel@tonic-gate 	 * search for the longest path in epname which contains
2877c478bd9Sstevel@tonic-gate 	 * oldnode->u.event.epname.  set npend to point to just past the
2887c478bd9Sstevel@tonic-gate 	 * end of this path.
2897c478bd9Sstevel@tonic-gate 	 */
2907c478bd9Sstevel@tonic-gate 	npend = NULL;
2917c478bd9Sstevel@tonic-gate 	for (npref = epname; npref; npref = npref->u.name.next) {
2927c478bd9Sstevel@tonic-gate 		if (npref->u.name.s == oldepname->u.name.s) {
2937c478bd9Sstevel@tonic-gate 			for (np1 = npref, np2 = oldepname;
2947c478bd9Sstevel@tonic-gate 			    np1 != NULL && np2 != NULL;
2957c478bd9Sstevel@tonic-gate 			    np1 = np1->u.name.next, np2 = np2->u.name.next) {
2967c478bd9Sstevel@tonic-gate 				if (np1->u.name.s != np2->u.name.s)
2977c478bd9Sstevel@tonic-gate 					break;
2987c478bd9Sstevel@tonic-gate 			}
2997c478bd9Sstevel@tonic-gate 			if (np2 == NULL) {
3007c478bd9Sstevel@tonic-gate 				foundmatch = 1;
3017c478bd9Sstevel@tonic-gate 				npend = np1;
3027c478bd9Sstevel@tonic-gate 				if (np1 == NULL) {
3037c478bd9Sstevel@tonic-gate 					/* oldepname matched npref up to end */
3047c478bd9Sstevel@tonic-gate 					break;
3057c478bd9Sstevel@tonic-gate 				}
3067c478bd9Sstevel@tonic-gate 			}
3077c478bd9Sstevel@tonic-gate 		}
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	if (foundmatch == 0) {
3117c478bd9Sstevel@tonic-gate 		/*
3127c478bd9Sstevel@tonic-gate 		 * if oldepname could not be found in epname, return a
3137c478bd9Sstevel@tonic-gate 		 * duplicate of the former.  do not try to instantize
3147c478bd9Sstevel@tonic-gate 		 * oldepname since it might not be a path.
3157c478bd9Sstevel@tonic-gate 		 */
3167c478bd9Sstevel@tonic-gate 		return (tname_dup(oldepname, CN_DUP));
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/*
3207c478bd9Sstevel@tonic-gate 	 * dup (epname -- npend).  all children should be T_NUMs.
3217c478bd9Sstevel@tonic-gate 	 */
3227c478bd9Sstevel@tonic-gate 	for (npref = epname;
3237c478bd9Sstevel@tonic-gate 	    ! (npref == NULL || npref == npend);
3247c478bd9Sstevel@tonic-gate 	    npref = npref->u.name.next) {
3257c478bd9Sstevel@tonic-gate 		struct node *newnp = newnode(T_NAME, oldepname->file,
3267c478bd9Sstevel@tonic-gate 		    oldepname->line);
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 		newnp->u.name.t = npref->u.name.t;
3297c478bd9Sstevel@tonic-gate 		newnp->u.name.s = npref->u.name.s;
3307c478bd9Sstevel@tonic-gate 		newnp->u.name.last = newnp;
3317c478bd9Sstevel@tonic-gate 		newnp->u.name.it = npref->u.name.it;
3327c478bd9Sstevel@tonic-gate 		newnp->u.name.cp = npref->u.name.cp;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 		newnp->u.name.child = newnode(T_NUM, oldepname->file,
3357c478bd9Sstevel@tonic-gate 		    oldepname->line);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 		if (npref->u.name.child == NULL ||
3387c478bd9Sstevel@tonic-gate 		    npref->u.name.child->t != T_NUM) {
3397c478bd9Sstevel@tonic-gate 			int childnum;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 			ASSERT(npref->u.name.cp != NULL);
3427c478bd9Sstevel@tonic-gate 			config_getcompname(npref->u.name.cp, NULL, &childnum);
3437c478bd9Sstevel@tonic-gate 			newnp->u.name.child->u.ull = childnum;
3447c478bd9Sstevel@tonic-gate 		} else {
3457c478bd9Sstevel@tonic-gate 			newnp->u.name.child->u.ull =
3467c478bd9Sstevel@tonic-gate 			    npref->u.name.child->u.ull;
3477c478bd9Sstevel@tonic-gate 		}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 		if (ret == NULL) {
3507c478bd9Sstevel@tonic-gate 			ret = newnp;
3517c478bd9Sstevel@tonic-gate 		} else {
3527c478bd9Sstevel@tonic-gate 			ret->u.name.last->u.name.next = newnp;
3537c478bd9Sstevel@tonic-gate 			ret->u.name.last = newnp;
3547c478bd9Sstevel@tonic-gate 		}
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	return (ret);
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate  * restriction: oldnode->u.event.epname has to be equivalent to or a subset
3627c478bd9Sstevel@tonic-gate  * of epname
3637c478bd9Sstevel@tonic-gate  */
3647c478bd9Sstevel@tonic-gate static struct node *
tevent_dup_to_epname(struct node * oldnode,struct node * epname)3657c478bd9Sstevel@tonic-gate tevent_dup_to_epname(struct node *oldnode, struct node *epname)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	struct node *ret;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	ret = newnode(T_EVENT, oldnode->file, oldnode->line);
3707c478bd9Sstevel@tonic-gate 	ret->u.event.ename = tname_dup(oldnode->u.event.ename, CN_NONE);
3717c478bd9Sstevel@tonic-gate 	ret->u.event.epname = tname_dup_to_epname(oldnode->u.event.epname,
3727c478bd9Sstevel@tonic-gate 	    epname);
3737c478bd9Sstevel@tonic-gate 	return (ret);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate static void
nv_instantiate(void * name,void * val,void * arg)3777c478bd9Sstevel@tonic-gate nv_instantiate(void *name, void *val, void *arg)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	struct prop_wlk_data *pd = (struct prop_wlk_data *)arg;
3807c478bd9Sstevel@tonic-gate 	struct node *orhs = (struct node *)val;
3817c478bd9Sstevel@tonic-gate 	struct node *nrhs;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	/* handle engines by instantizing the entire engine */
3847c478bd9Sstevel@tonic-gate 	if (name == L_engine) {
3857c478bd9Sstevel@tonic-gate 		ASSERT(orhs->t == T_EVENT);
3867c478bd9Sstevel@tonic-gate 		ASSERT(orhs->u.event.ename->u.name.t == N_SERD);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 		/* there are only SERD engines for now */
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 		nrhs = newnode(T_SERD, orhs->file, orhs->line);
3917c478bd9Sstevel@tonic-gate 		nrhs->u.stmt.np = tevent_dup_to_epname(orhs, pd->epname);
3927c478bd9Sstevel@tonic-gate 		nrhs->u.stmt.lutp = props2instance(orhs, pd->epname);
3937c478bd9Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
3947c478bd9Sstevel@tonic-gate 		return;
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	switch (orhs->t) {
3987c478bd9Sstevel@tonic-gate 	case T_NUM:
3997c478bd9Sstevel@tonic-gate 		nrhs = newnode(T_NUM, orhs->file, orhs->line);
4007c478bd9Sstevel@tonic-gate 		nrhs->u.ull = orhs->u.ull;
4017c478bd9Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4027c478bd9Sstevel@tonic-gate 		break;
4037c478bd9Sstevel@tonic-gate 	case T_TIMEVAL:
4047c478bd9Sstevel@tonic-gate 		nrhs = newnode(T_TIMEVAL, orhs->file, orhs->line);
4057c478bd9Sstevel@tonic-gate 		nrhs->u.ull = orhs->u.ull;
4067c478bd9Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4077c478bd9Sstevel@tonic-gate 		break;
4087c478bd9Sstevel@tonic-gate 	case T_NAME:
4097c478bd9Sstevel@tonic-gate 		nrhs = tname_dup_to_epname(orhs, pd->epname);
4107c478bd9Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4117c478bd9Sstevel@tonic-gate 		break;
4127c478bd9Sstevel@tonic-gate 	case T_EVENT:
4137c478bd9Sstevel@tonic-gate 		nrhs = tevent_dup_to_epname(orhs, pd->epname);
4147c478bd9Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4157c478bd9Sstevel@tonic-gate 		break;
4167aec1d6eScindi 	case T_GLOBID:
4177aec1d6eScindi 		nrhs = newnode(T_GLOBID, orhs->file, orhs->line);
4187aec1d6eScindi 		nrhs->u.globid.s = orhs->u.globid.s;
4197aec1d6eScindi 		pd->props = lut_add(pd->props, name, nrhs, NULL);
4207aec1d6eScindi 		break;
4217aec1d6eScindi 	case T_FUNC:
4227aec1d6eScindi 		/* for T_FUNC, we don't duplicate it, just point to node */
4237aec1d6eScindi 		pd->props = lut_add(pd->props, name, orhs, NULL);
4247aec1d6eScindi 		break;
4257c478bd9Sstevel@tonic-gate 	default:
4267aec1d6eScindi 		out(O_DIE, "unexpected nvpair value type %s",
4277c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(((struct node *)val)->t));
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate static struct lut *
props2instance(struct node * eventnp,struct node * epname)4327c478bd9Sstevel@tonic-gate props2instance(struct node *eventnp, struct node *epname)
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate 	struct prop_wlk_data pd;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	pd.props = NULL;
4377c478bd9Sstevel@tonic-gate 	pd.epname = epname;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	ASSERT(eventnp->u.event.declp != NULL);
4407c478bd9Sstevel@tonic-gate 	lut_walk(eventnp->u.event.declp->u.stmt.lutp, nv_instantiate, &pd);
4417c478bd9Sstevel@tonic-gate 	return (pd.props);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4457c478bd9Sstevel@tonic-gate static void
instances_destructor(void * left,void * right,void * arg)4467c478bd9Sstevel@tonic-gate instances_destructor(void *left, void *right, void *arg)
4477c478bd9Sstevel@tonic-gate {
4487c478bd9Sstevel@tonic-gate 	struct node *dn = (struct node *)right;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	if (dn->t == T_SERD) {
4517c478bd9Sstevel@tonic-gate 		/* we allocated the lut during itree_create(), so free it */
4527c478bd9Sstevel@tonic-gate 		lut_free(dn->u.stmt.lutp, instances_destructor, NULL);
4537c478bd9Sstevel@tonic-gate 		dn->u.stmt.lutp = NULL;
4547c478bd9Sstevel@tonic-gate 	}
4557aec1d6eScindi 	if (dn->t != T_FUNC)	/* T_FUNC pointed to original node */
4567c478bd9Sstevel@tonic-gate 		tree_free(dn);
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate 
4597aec1d6eScindi /*ARGSUSED*/
4607aec1d6eScindi static void
payloadprops_destructor(void * left,void * right,void * arg)4617aec1d6eScindi payloadprops_destructor(void *left, void *right, void *arg)
4627aec1d6eScindi {
4637aec1d6eScindi 	FREE(right);
4647aec1d6eScindi }
4657aec1d6eScindi 
466b7d3956bSstephh /*ARGSUSED*/
467b7d3956bSstephh static void
serdprops_destructor(void * left,void * right,void * arg)468b7d3956bSstephh serdprops_destructor(void *left, void *right, void *arg)
469b7d3956bSstephh {
470b7d3956bSstephh 	FREE(right);
471b7d3956bSstephh }
472b7d3956bSstephh 
4737c478bd9Sstevel@tonic-gate /*
4747c478bd9Sstevel@tonic-gate  * event_cmp -- used via lut_lookup/lut_add on instance tree lut
4757c478bd9Sstevel@tonic-gate  */
4767c478bd9Sstevel@tonic-gate static int
event_cmp(struct event * ep1,struct event * ep2)4777c478bd9Sstevel@tonic-gate event_cmp(struct event *ep1, struct event *ep2)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 	int diff;
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	if ((diff = ep2->enode->u.event.ename->u.name.s -
4827c478bd9Sstevel@tonic-gate 	    ep1->enode->u.event.ename->u.name.s) != 0)
4837c478bd9Sstevel@tonic-gate 		return (diff);
4847c478bd9Sstevel@tonic-gate 	if ((diff = (char *)ep2->ipp - (char *)ep1->ipp) != 0)
4857c478bd9Sstevel@tonic-gate 		return (diff);
4867c478bd9Sstevel@tonic-gate 	return (0);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate struct event *
itree_lookup(struct lut * itp,const char * ename,const struct ipath * ipp)4917c478bd9Sstevel@tonic-gate itree_lookup(struct lut *itp, const char *ename, const struct ipath *ipp)
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate 	struct event searchevent;	/* just used for searching */
4947c478bd9Sstevel@tonic-gate 	struct node searcheventnode;
4957c478bd9Sstevel@tonic-gate 	struct node searchenamenode;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	searchevent.enode = &searcheventnode;
4987c478bd9Sstevel@tonic-gate 	searcheventnode.t = T_EVENT;
4997c478bd9Sstevel@tonic-gate 	searcheventnode.u.event.ename = &searchenamenode;
5007c478bd9Sstevel@tonic-gate 	searchenamenode.t = T_NAME;
5017c478bd9Sstevel@tonic-gate 	searchenamenode.u.name.s = ename;
5027c478bd9Sstevel@tonic-gate 	searchevent.ipp = ipp;
5037c478bd9Sstevel@tonic-gate 	return (lut_lookup(itp, (void *)&searchevent, (lut_cmp)event_cmp));
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate static struct event *
find_or_add_event(struct info * infop,struct node * np)5077c478bd9Sstevel@tonic-gate find_or_add_event(struct info *infop, struct node *np)
5087c478bd9Sstevel@tonic-gate {
5097c478bd9Sstevel@tonic-gate 	struct event *ret;
5107c478bd9Sstevel@tonic-gate 	struct event searchevent;	/* just used for searching */
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	ASSERTeq(np->t, T_EVENT, ptree_nodetype2str);
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	searchevent.enode = np;
5157c478bd9Sstevel@tonic-gate 	searchevent.ipp = ipath(np->u.event.epname);
5167c478bd9Sstevel@tonic-gate 	if ((ret = lut_lookup(infop->lut, (void *)&searchevent,
5177c478bd9Sstevel@tonic-gate 	    (lut_cmp)event_cmp)) != NULL)
5187c478bd9Sstevel@tonic-gate 		return (ret);
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	/* wasn't already in tree, allocate it */
521b5016cbbSstephh 	ret = alloc_xmalloc(sizeof (*ret));
5227c478bd9Sstevel@tonic-gate 	bzero(ret, sizeof (*ret));
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	ret->t = np->u.event.ename->u.name.t;
5257c478bd9Sstevel@tonic-gate 	ret->enode = np;
5267c478bd9Sstevel@tonic-gate 	ret->ipp = searchevent.ipp;
5277c478bd9Sstevel@tonic-gate 	ret->props = props2instance(np, np->u.event.epname);
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	infop->lut = lut_add(infop->lut, (void *)ret, (void *)ret,
5307c478bd9Sstevel@tonic-gate 	    (lut_cmp)event_cmp);
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	return (ret);
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate /*
536*26733bfeSStephen Hanson  * Used for handling expansions where first part of oldepname is a horizontal
537*26733bfeSStephen Hanson  * expansion. Recurses through entire tree. oldepname argument is always the
538*26733bfeSStephen Hanson  * full path as in the rules. Once we find a match we go back to using
539*26733bfeSStephen Hanson  * hmatch_event to handle the rest.
540*26733bfeSStephen Hanson  */
541*26733bfeSStephen Hanson static void
hmatch_full_config(struct info * infop,struct node * eventnp,struct node * oldepname,struct config * ncp,struct node * nextnp,struct iterinfo * iterinfop)542*26733bfeSStephen Hanson hmatch_full_config(struct info *infop, struct node *eventnp,
543*26733bfeSStephen Hanson     struct node *oldepname, struct config *ncp, struct node *nextnp,
544*26733bfeSStephen Hanson     struct iterinfo *iterinfop)
545*26733bfeSStephen Hanson {
546*26733bfeSStephen Hanson 	char *cp_s;
547*26733bfeSStephen Hanson 	int cp_num;
548*26733bfeSStephen Hanson 	struct config *cp;
549*26733bfeSStephen Hanson 	struct node *saved_ewname;
550*26733bfeSStephen Hanson 	struct node *saved_epname;
551*26733bfeSStephen Hanson 	struct config *pcp, *ocp;
552*26733bfeSStephen Hanson 	struct node *cpnode;
553*26733bfeSStephen Hanson 	struct node *ewlp, *ewfp;
554*26733bfeSStephen Hanson 
555*26733bfeSStephen Hanson 	for (cp = ncp; cp; cp = config_next(cp)) {
556*26733bfeSStephen Hanson 		config_getcompname(cp, &cp_s, &cp_num);
557*26733bfeSStephen Hanson 		if (cp_s == oldepname->u.name.s) {
558*26733bfeSStephen Hanson 			/*
559*26733bfeSStephen Hanson 			 * Found one.
560*26733bfeSStephen Hanson 			 */
561*26733bfeSStephen Hanson 			iterinfop->num = cp_num;
562*26733bfeSStephen Hanson 
563*26733bfeSStephen Hanson 			/*
564*26733bfeSStephen Hanson 			 * Need to set ewname, epname for correct node as is
565*26733bfeSStephen Hanson 			 * needed by constraint path matching. This code is
566*26733bfeSStephen Hanson 			 * similar to that in vmatch_event.
567*26733bfeSStephen Hanson 			 */
568*26733bfeSStephen Hanson 			saved_ewname = eventnp->u.event.ewname;
569*26733bfeSStephen Hanson 			saved_epname = eventnp->u.event.epname;
570*26733bfeSStephen Hanson 			ocp = oldepname->u.name.cp;
571*26733bfeSStephen Hanson 
572*26733bfeSStephen Hanson 			/*
573*26733bfeSStephen Hanson 			 * Find correct ewname by walking back up the config
574*26733bfeSStephen Hanson 			 * tree adding each name portion as we go.
575*26733bfeSStephen Hanson 			 */
576*26733bfeSStephen Hanson 			pcp = config_parent(cp);
577*26733bfeSStephen Hanson 			eventnp->u.event.ewname = NULL;
578*26733bfeSStephen Hanson 			for (; pcp != infop->croot; pcp = config_parent(pcp)) {
579*26733bfeSStephen Hanson 				config_getcompname(pcp, &cp_s, &cp_num);
580*26733bfeSStephen Hanson 				cpnode = tree_name(cp_s, IT_NONE, NULL, 0);
581*26733bfeSStephen Hanson 				cpnode->u.name.child = newnode(T_NUM, NULL, 0);
582*26733bfeSStephen Hanson 				cpnode->u.name.child->u.ull = cp_num;
583*26733bfeSStephen Hanson 				cpnode->u.name.cp = pcp;
584*26733bfeSStephen Hanson 				if (eventnp->u.event.ewname != NULL) {
585*26733bfeSStephen Hanson 					cpnode->u.name.next =
586*26733bfeSStephen Hanson 					    eventnp->u.event.ewname;
587*26733bfeSStephen Hanson 					cpnode->u.name.last =
588*26733bfeSStephen Hanson 					    eventnp->u.event.ewname->
589*26733bfeSStephen Hanson 					    u.name.last;
590*26733bfeSStephen Hanson 				}
591*26733bfeSStephen Hanson 				eventnp->u.event.ewname = cpnode;
592*26733bfeSStephen Hanson 			}
593*26733bfeSStephen Hanson 
594*26733bfeSStephen Hanson 			/*
595*26733bfeSStephen Hanson 			 * Now create correct epname by duping new ewname
596*26733bfeSStephen Hanson 			 * and appending oldepname.
597*26733bfeSStephen Hanson 			 */
598*26733bfeSStephen Hanson 			ewfp = tname_dup(eventnp->u.event.ewname, CN_DUP);
599*26733bfeSStephen Hanson 			ewlp = ewfp->u.name.last;
600*26733bfeSStephen Hanson 			ewfp->u.name.last = oldepname->u.name.last;
601*26733bfeSStephen Hanson 			ewlp->u.name.next = oldepname;
602*26733bfeSStephen Hanson 			oldepname->u.name.cp = cp;
603*26733bfeSStephen Hanson 			eventnp->u.event.epname = ewfp;
604*26733bfeSStephen Hanson 
605*26733bfeSStephen Hanson 			outfl(O_ALTFP|O_VERB3|O_NONL, infop->anp->file,
606*26733bfeSStephen Hanson 			    infop->anp->line, "hmatch_full_config: ");
607*26733bfeSStephen Hanson 			ptree_name_iter(O_ALTFP|O_VERB3|O_NONL,
608*26733bfeSStephen Hanson 			    eventnp->u.event.epname);
609*26733bfeSStephen Hanson 			out(O_ALTFP|O_VERB3, NULL);
610*26733bfeSStephen Hanson 
611*26733bfeSStephen Hanson 			/*
612*26733bfeSStephen Hanson 			 * Now complete hmatch.
613*26733bfeSStephen Hanson 			 */
614*26733bfeSStephen Hanson 			hmatch_event(infop, eventnp, oldepname->u.name.next,
615*26733bfeSStephen Hanson 			    config_child(cp), nextnp, 1);
616*26733bfeSStephen Hanson 
617*26733bfeSStephen Hanson 			/*
618*26733bfeSStephen Hanson 			 * set everything back again
619*26733bfeSStephen Hanson 			 */
620*26733bfeSStephen Hanson 			oldepname->u.name.cp = ocp;
621*26733bfeSStephen Hanson 			iterinfop->num = -1;
622*26733bfeSStephen Hanson 			ewlp->u.name.next = NULL;
623*26733bfeSStephen Hanson 			ewfp->u.name.last = ewlp;
624*26733bfeSStephen Hanson 			tree_free(ewfp);
625*26733bfeSStephen Hanson 			tree_free(eventnp->u.event.ewname);
626*26733bfeSStephen Hanson 			eventnp->u.event.ewname = saved_ewname;
627*26733bfeSStephen Hanson 			eventnp->u.event.epname = saved_epname;
628*26733bfeSStephen Hanson 		}
629*26733bfeSStephen Hanson 		/*
630*26733bfeSStephen Hanson 		 * Try the next level down.
631*26733bfeSStephen Hanson 		 */
632*26733bfeSStephen Hanson 		hmatch_full_config(infop, eventnp,
633*26733bfeSStephen Hanson 		    oldepname, config_child(cp), nextnp, iterinfop);
634*26733bfeSStephen Hanson 	}
635*26733bfeSStephen Hanson }
636*26733bfeSStephen Hanson 
637*26733bfeSStephen Hanson /*
6387c478bd9Sstevel@tonic-gate  * hmatch_event -- perform any appropriate horizontal expansion on an event
6397c478bd9Sstevel@tonic-gate  *
6407c478bd9Sstevel@tonic-gate  * this routine is used to perform horizontal expansion on both the
6417c478bd9Sstevel@tonic-gate  * left-hand-side events in a prop, and the right-hand-side events.
6427c478bd9Sstevel@tonic-gate  * when called to handle a left-side event, nextnp point to the right
6437c478bd9Sstevel@tonic-gate  * side of the prop that should be passed to hmatch() for each match
6447c478bd9Sstevel@tonic-gate  * found by horizontal expansion.   when no horizontal expansion exists,
6457c478bd9Sstevel@tonic-gate  * we will still "match" one event for every event found in the list on
6467c478bd9Sstevel@tonic-gate  * the left-hand-side of the prop because vmatch() already found that
6477c478bd9Sstevel@tonic-gate  * there's at least one match during vertical expansion.
6487c478bd9Sstevel@tonic-gate  */
6497c478bd9Sstevel@tonic-gate static void
hmatch_event(struct info * infop,struct node * eventnp,struct node * epname,struct config * ncp,struct node * nextnp,int rematch)6507c478bd9Sstevel@tonic-gate hmatch_event(struct info *infop, struct node *eventnp, struct node *epname,
6517c478bd9Sstevel@tonic-gate     struct config *ncp, struct node *nextnp, int rematch)
6527c478bd9Sstevel@tonic-gate {
6537c478bd9Sstevel@tonic-gate 	if (epname == NULL) {
6547c478bd9Sstevel@tonic-gate 		/*
6557c478bd9Sstevel@tonic-gate 		 * end of pathname recursion, either we just located
6567c478bd9Sstevel@tonic-gate 		 * a left-hand-side event and we're ready to move on
6577c478bd9Sstevel@tonic-gate 		 * to the expanding the right-hand-side events, or
6587c478bd9Sstevel@tonic-gate 		 * we're further down the recursion and we just located
6597c478bd9Sstevel@tonic-gate 		 * a right-hand-side event.  the passed-in parameter
6607c478bd9Sstevel@tonic-gate 		 * "nextnp" tells us whether we're working on the left
6617c478bd9Sstevel@tonic-gate 		 * side and need to move on to nextnp, or if nextnp is
6627c478bd9Sstevel@tonic-gate 		 * NULL, we're working on the right side.
6637c478bd9Sstevel@tonic-gate 		 */
6647c478bd9Sstevel@tonic-gate 		if (nextnp) {
6657c478bd9Sstevel@tonic-gate 			/*
6667c478bd9Sstevel@tonic-gate 			 * finished a left side expansion, move on to right.
6677c478bd9Sstevel@tonic-gate 			 * tell generate() what event we just matched so
6687c478bd9Sstevel@tonic-gate 			 * it can be used at the source of any arrows
6697c478bd9Sstevel@tonic-gate 			 * we generate as we match events on the right side.
6707c478bd9Sstevel@tonic-gate 			 */
671b5016cbbSstephh 			generate_from(eventnp);
6727c478bd9Sstevel@tonic-gate 			hmatch(infop, nextnp, NULL);
6737c478bd9Sstevel@tonic-gate 		} else {
6747c478bd9Sstevel@tonic-gate 			/*
6757c478bd9Sstevel@tonic-gate 			 * finished a right side expansion.  tell generate
6767c478bd9Sstevel@tonic-gate 			 * the information about the destination and let
6777c478bd9Sstevel@tonic-gate 			 * it construct the arrows as appropriate.
6787c478bd9Sstevel@tonic-gate 			 */
679b5016cbbSstephh 			generate_to(eventnp);
680b5016cbbSstephh 			generate(infop);
6817c478bd9Sstevel@tonic-gate 		}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 		return;
6847c478bd9Sstevel@tonic-gate 	}
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	ASSERTeq(epname->t, T_NAME, ptree_nodetype2str);
6877c478bd9Sstevel@tonic-gate 
688b7d3956bSstephh 	if (epname->u.name.cp == NULL)
689b7d3956bSstephh 		return;
690b7d3956bSstephh 
6917c478bd9Sstevel@tonic-gate 	/*
6927c478bd9Sstevel@tonic-gate 	 * we only get here when eventnp already has a completely
6937c478bd9Sstevel@tonic-gate 	 * instanced epname in it already.  so we first recurse
6947c478bd9Sstevel@tonic-gate 	 * down to the end of the name and as the recursion pops
6957c478bd9Sstevel@tonic-gate 	 * up, we look for opportunities to advance horizontal
696b5016cbbSstephh 	 * expansions on to the next match.
6977c478bd9Sstevel@tonic-gate 	 */
698b5016cbbSstephh 	if (epname->u.name.it == IT_HORIZONTAL || rematch) {
6997c478bd9Sstevel@tonic-gate 		struct config *cp;
7007c478bd9Sstevel@tonic-gate 		struct config *ocp = epname->u.name.cp;
7017c478bd9Sstevel@tonic-gate 		char *cp_s;
7027c478bd9Sstevel@tonic-gate 		int cp_num;
7037c478bd9Sstevel@tonic-gate 		int ocp_num;
7047c478bd9Sstevel@tonic-gate 		struct iterinfo *iterinfop = NULL;
7057c478bd9Sstevel@tonic-gate 		const char *iters;
706b5016cbbSstephh 		int hexpand = 0;
7077c478bd9Sstevel@tonic-gate 
708b5016cbbSstephh 		if (epname->u.name.it != IT_HORIZONTAL) {
709b5016cbbSstephh 			/*
710b5016cbbSstephh 			 * Ancestor was horizontal though, so must rematch
711b5016cbbSstephh 			 * against the name/num found in vmatch.
712b5016cbbSstephh 			 */
7137c478bd9Sstevel@tonic-gate 			config_getcompname(ocp, NULL, &ocp_num);
714b5016cbbSstephh 		} else {
7157c478bd9Sstevel@tonic-gate 			iters = epname->u.name.child->u.name.s;
7167c478bd9Sstevel@tonic-gate 			if ((iterinfop = lut_lookup(infop->ex,
7177c478bd9Sstevel@tonic-gate 			    (void *)iters, NULL)) == NULL) {
718b5016cbbSstephh 				/*
719b5016cbbSstephh 				 * do horizontal expansion on this node
720b5016cbbSstephh 				 */
721b5016cbbSstephh 				hexpand = 1;
722b5016cbbSstephh 				iterinfop = alloc_xmalloc(
723b5016cbbSstephh 				    sizeof (struct iterinfo));
724b5016cbbSstephh 				iterinfop->num = -1;
725b5016cbbSstephh 				iterinfop->np = epname;
726b5016cbbSstephh 				infop->ex = lut_add(infop->ex, (void *)iters,
727b5016cbbSstephh 				    iterinfop, NULL);
728b5016cbbSstephh 			} else if (iterinfop->num == -1) {
729b5016cbbSstephh 				hexpand = 1;
7307c478bd9Sstevel@tonic-gate 			} else {
731b5016cbbSstephh 				/*
732b5016cbbSstephh 				 * This name has already been used in a
733b5016cbbSstephh 				 * horizontal expansion. This time just match it
734b5016cbbSstephh 				 */
735b5016cbbSstephh 				ocp_num = iterinfop->num;
7367c478bd9Sstevel@tonic-gate 			}
737b5016cbbSstephh 		}
738b5016cbbSstephh 		/*
739*26733bfeSStephen Hanson 		 * handle case where this is the first section of oldepname
740*26733bfeSStephen Hanson 		 * and it is horizontally expanded. Instead of just looking for
741*26733bfeSStephen Hanson 		 * siblings, we want to scan the entire config tree for further
742*26733bfeSStephen Hanson 		 * matches.
743*26733bfeSStephen Hanson 		 */
744*26733bfeSStephen Hanson 		if (epname == eventnp->u.event.oldepname &&
745*26733bfeSStephen Hanson 		    epname->u.name.it == IT_HORIZONTAL) {
746*26733bfeSStephen Hanson 			/*
747*26733bfeSStephen Hanson 			 * Run through config looking for any that match the
748*26733bfeSStephen Hanson 			 * name.
749*26733bfeSStephen Hanson 			 */
750*26733bfeSStephen Hanson 			hmatch_full_config(infop, eventnp, epname,
751*26733bfeSStephen Hanson 			    infop->croot, nextnp, iterinfop);
752*26733bfeSStephen Hanson 			return;
753*26733bfeSStephen Hanson 		}
754*26733bfeSStephen Hanson 
755*26733bfeSStephen Hanson 		/*
756b5016cbbSstephh 		 * Run through siblings looking for any that match the name.
757b5016cbbSstephh 		 * If hexpand not set then num must also match ocp_num.
758b5016cbbSstephh 		 */
759b5016cbbSstephh 		for (cp = rematch ? ncp : ocp; cp; cp = config_next(cp)) {
760b5016cbbSstephh 			config_getcompname(cp, &cp_s, &cp_num);
761b5016cbbSstephh 			if (cp_s == epname->u.name.s) {
762b5016cbbSstephh 				if (hexpand)
763b5016cbbSstephh 					iterinfop->num = cp_num;
764b5016cbbSstephh 				else if (ocp_num != cp_num)
765b5016cbbSstephh 					continue;
7667c478bd9Sstevel@tonic-gate 				epname->u.name.cp = cp;
7677c478bd9Sstevel@tonic-gate 				hmatch_event(infop, eventnp,
7687c478bd9Sstevel@tonic-gate 				    epname->u.name.next, config_child(cp),
7697c478bd9Sstevel@tonic-gate 				    nextnp, 1);
7707c478bd9Sstevel@tonic-gate 			}
7717c478bd9Sstevel@tonic-gate 		}
7727c478bd9Sstevel@tonic-gate 		epname->u.name.cp = ocp;
773b5016cbbSstephh 		if (hexpand)
774b5016cbbSstephh 			iterinfop->num = -1;
775b5016cbbSstephh 	} else {
776b5016cbbSstephh 		hmatch_event(infop, eventnp, epname->u.name.next,
777b5016cbbSstephh 		    NULL, nextnp, 0);
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate }
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate /*
7827c478bd9Sstevel@tonic-gate  * hmatch -- check for horizontal expansion matches
7837c478bd9Sstevel@tonic-gate  *
7847c478bd9Sstevel@tonic-gate  * np points to the things we're matching (like a T_LIST or a T_EVENT)
7857c478bd9Sstevel@tonic-gate  * and if we're working on a left-side of a prop, nextnp points to
7867c478bd9Sstevel@tonic-gate  * the other side of the prop that we'll tackle next when this recursion
7877c478bd9Sstevel@tonic-gate  * bottoms out.  when all the events in the entire prop arrow have been
7887c478bd9Sstevel@tonic-gate  * horizontally expanded, generate() will be called to generate the
7897c478bd9Sstevel@tonic-gate  * actualy arrow.
7907c478bd9Sstevel@tonic-gate  */
7917c478bd9Sstevel@tonic-gate static void
hmatch(struct info * infop,struct node * np,struct node * nextnp)7927c478bd9Sstevel@tonic-gate hmatch(struct info *infop, struct node *np, struct node *nextnp)
7937c478bd9Sstevel@tonic-gate {
7947c478bd9Sstevel@tonic-gate 	if (np == NULL)
7957c478bd9Sstevel@tonic-gate 		return;		/* all done */
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	/*
7987c478bd9Sstevel@tonic-gate 	 * for each item in the list of events (which could just
7997c478bd9Sstevel@tonic-gate 	 * be a single event, or it could get larger in the loop
8007c478bd9Sstevel@tonic-gate 	 * below due to horizontal expansion), call hmatch on
8017c478bd9Sstevel@tonic-gate 	 * the right side and create arrows to each element.
8027c478bd9Sstevel@tonic-gate 	 */
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	switch (np->t) {
8057c478bd9Sstevel@tonic-gate 	case T_LIST:
8067c478bd9Sstevel@tonic-gate 		/* loop through the list */
8077c478bd9Sstevel@tonic-gate 		if (np->u.expr.left)
8087c478bd9Sstevel@tonic-gate 			hmatch(infop, np->u.expr.left, nextnp);
8097c478bd9Sstevel@tonic-gate 		if (np->u.expr.right)
8107c478bd9Sstevel@tonic-gate 			hmatch(infop, np->u.expr.right, nextnp);
8117c478bd9Sstevel@tonic-gate 		break;
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	case T_EVENT:
8147c478bd9Sstevel@tonic-gate 		hmatch_event(infop, np, np->u.event.epname,
8157c478bd9Sstevel@tonic-gate 		    NULL, nextnp, 0);
8167c478bd9Sstevel@tonic-gate 		break;
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	default:
8197c478bd9Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
8207c478bd9Sstevel@tonic-gate 		    "hmatch: unexpected type: %s",
8217c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
8227c478bd9Sstevel@tonic-gate 	}
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate static int
itree_np2nork(struct node * norknp)8267c478bd9Sstevel@tonic-gate itree_np2nork(struct node *norknp)
8277c478bd9Sstevel@tonic-gate {
8287c478bd9Sstevel@tonic-gate 	if (norknp == NULL)
8297c478bd9Sstevel@tonic-gate 		return (1);
8307c478bd9Sstevel@tonic-gate 	else if (norknp->t == T_NAME && norknp->u.name.s == L_A)
8317c478bd9Sstevel@tonic-gate 		return (-1);	/* our internal version of "all" */
8327c478bd9Sstevel@tonic-gate 	else if (norknp->t == T_NUM)
8337c478bd9Sstevel@tonic-gate 		return ((int)norknp->u.ull);
8347c478bd9Sstevel@tonic-gate 	else
835b5016cbbSstephh 		outfl(O_DIE, norknp->file, norknp->line,
8367c478bd9Sstevel@tonic-gate 		    "itree_np2nork: internal error type %s",
8377c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(norknp->t));
8387c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
83980ab886dSwesolows 	return (1);
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate static struct iterinfo *
newiterinfo(int num,struct node * np)8437c478bd9Sstevel@tonic-gate newiterinfo(int num, struct node *np)
8447c478bd9Sstevel@tonic-gate {
845b5016cbbSstephh 	struct iterinfo *ret = alloc_xmalloc(sizeof (*ret));
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	ret->num = num;
8487c478bd9Sstevel@tonic-gate 	ret->np = np;
8497c478bd9Sstevel@tonic-gate 	return (ret);
8507c478bd9Sstevel@tonic-gate }
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8537c478bd9Sstevel@tonic-gate static void
iterinfo_destructor(void * left,void * right,void * arg)8547c478bd9Sstevel@tonic-gate iterinfo_destructor(void *left, void *right, void *arg)
8557c478bd9Sstevel@tonic-gate {
8567c478bd9Sstevel@tonic-gate 	struct iterinfo *iterinfop = (struct iterinfo *)right;
8577c478bd9Sstevel@tonic-gate 
858b5016cbbSstephh 	alloc_xfree(iterinfop, sizeof (*iterinfop));
8597c478bd9Sstevel@tonic-gate }
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate static void
vmatch_event(struct info * infop,struct config * cp,struct node * np,struct node * lnp,struct node * anp,struct wildcardinfo * wcp)8627c478bd9Sstevel@tonic-gate vmatch_event(struct info *infop, struct config *cp, struct node *np,
863b5016cbbSstephh 	    struct node *lnp, struct node *anp, struct wildcardinfo *wcp)
8647c478bd9Sstevel@tonic-gate {
8657c478bd9Sstevel@tonic-gate 	char *cp_s;
8667c478bd9Sstevel@tonic-gate 	int cp_num;
867b5016cbbSstephh 	struct node *ewlp, *ewfp;
868b5016cbbSstephh 	struct config *pcp;
869b5016cbbSstephh 	struct node *cpnode;
870b5016cbbSstephh 	int newewname = 0;
8717c478bd9Sstevel@tonic-gate 
872*26733bfeSStephen Hanson 	/*
873*26733bfeSStephen Hanson 	 * handle case where the first section of the path name is horizontally
874*26733bfeSStephen Hanson 	 * expanded. The whole expansion is handled by hmatch on the first
875*26733bfeSStephen Hanson 	 * match here - so we just skip any subsequent matches here.
876*26733bfeSStephen Hanson 	 */
877*26733bfeSStephen Hanson 	if (wcp->got_wc_hz == 1)
878*26733bfeSStephen Hanson 		return;
879*26733bfeSStephen Hanson 
880b5016cbbSstephh 	if (np == NULL) {
8817c478bd9Sstevel@tonic-gate 		/*
882b5016cbbSstephh 		 * Reached the end of the name. u.name.cp pointers should be set
883b5016cbbSstephh 		 * up for each part of name. From this we can use config tree
884b5016cbbSstephh 		 * to build up the wildcard part of the name (if any).
8857c478bd9Sstevel@tonic-gate 		 */
886b5016cbbSstephh 		pcp = config_parent(wcp->nptop->u.event.epname->u.name.cp);
887b5016cbbSstephh 		if (pcp == infop->croot) {
888b5016cbbSstephh 			/*
889b5016cbbSstephh 			 * no wildcarding done - move on to next entry
890b5016cbbSstephh 			 */
891b5016cbbSstephh 			wcp->nptop->u.event.ewname = wcp->ewname;
892b5016cbbSstephh 			wcp->nptop->u.event.oldepname = wcp->oldepname;
893b5016cbbSstephh 			vmatch(infop, np, lnp, anp);
894*26733bfeSStephen Hanson 			wcp->got_wc_hz = 0;
8953e8d8e18Sdb35262 			return;
896b5016cbbSstephh 		}
897b5016cbbSstephh 		if (wcp->ewname == NULL) {
898b5016cbbSstephh 			/*
899b5016cbbSstephh 			 * ewname not yet set up - do it now
900b5016cbbSstephh 			 */
901b5016cbbSstephh 			newewname = 1;
902b5016cbbSstephh 			for (; pcp != infop->croot; pcp = config_parent(pcp)) {
903b5016cbbSstephh 				config_getcompname(pcp, &cp_s, &cp_num);
904b5016cbbSstephh 				cpnode = tree_name(cp_s, IT_NONE, NULL, 0);
905b5016cbbSstephh 				cpnode->u.name.child = newnode(T_NUM, NULL, 0);
906b5016cbbSstephh 				cpnode->u.name.child->u.ull = cp_num;
907b5016cbbSstephh 				cpnode->u.name.cp = pcp;
908b5016cbbSstephh 				if (wcp->ewname != NULL) {
909b5016cbbSstephh 					cpnode->u.name.next = wcp->ewname;
910b5016cbbSstephh 					cpnode->u.name.last =
911b5016cbbSstephh 					    wcp->ewname->u.name.last;
912b5016cbbSstephh 				}
913b5016cbbSstephh 				wcp->ewname = cpnode;
914b5016cbbSstephh 			}
915b5016cbbSstephh 		}
9163e8d8e18Sdb35262 
917b5016cbbSstephh 		/*
918b5016cbbSstephh 		 * dup ewname and append oldepname
919b5016cbbSstephh 		 */
920b5016cbbSstephh 		ewfp = tname_dup(wcp->ewname, CN_DUP);
921b5016cbbSstephh 		ewlp = ewfp->u.name.last;
922b5016cbbSstephh 		ewfp->u.name.last = wcp->oldepname->u.name.last;
923b5016cbbSstephh 		ewlp->u.name.next = wcp->oldepname;
9247c478bd9Sstevel@tonic-gate 
925b5016cbbSstephh 		wcp->nptop->u.event.epname = ewfp;
926b5016cbbSstephh 		wcp->nptop->u.event.ewname = wcp->ewname;
927b5016cbbSstephh 		wcp->nptop->u.event.oldepname = wcp->oldepname;
928b5016cbbSstephh 		vmatch(infop, np, lnp, anp);
929*26733bfeSStephen Hanson 		wcp->got_wc_hz = 0;
930b5016cbbSstephh 		wcp->nptop->u.event.epname = wcp->oldepname;
931b5016cbbSstephh 
932b5016cbbSstephh 		/*
933b5016cbbSstephh 		 * reduce duped ewname to original then free
934b5016cbbSstephh 		 */
935b5016cbbSstephh 		ewlp->u.name.next = NULL;
936b5016cbbSstephh 		ewfp->u.name.last = ewlp;
937b5016cbbSstephh 		tree_free(ewfp);
938b5016cbbSstephh 
939b5016cbbSstephh 		if (newewname) {
940b5016cbbSstephh 			/*
941b5016cbbSstephh 			 * free ewname if allocated above
942b5016cbbSstephh 			 */
943b5016cbbSstephh 			tree_free(wcp->ewname);
944b5016cbbSstephh 			wcp->ewname = NULL;
945b5016cbbSstephh 		}
9467c478bd9Sstevel@tonic-gate 		return;
9477c478bd9Sstevel@tonic-gate 	}
9487c478bd9Sstevel@tonic-gate 
949b5016cbbSstephh 	/*
950b5016cbbSstephh 	 * We have an np. See if we can match it in this section of
951b5016cbbSstephh 	 * the config tree.
952b5016cbbSstephh 	 */
9537c478bd9Sstevel@tonic-gate 	if (cp == NULL)
9547c478bd9Sstevel@tonic-gate 		return;	/* no more config to match against */
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	for (; cp; cp = config_next(cp)) {
9577c478bd9Sstevel@tonic-gate 		config_getcompname(cp, &cp_s, &cp_num);
9587c478bd9Sstevel@tonic-gate 
959b5016cbbSstephh 		if (cp_s == np->u.name.s) {
9607c478bd9Sstevel@tonic-gate 			/* found a matching component name */
9617c478bd9Sstevel@tonic-gate 			if (np->u.name.child &&
9627c478bd9Sstevel@tonic-gate 			    np->u.name.child->t == T_NUM) {
9637c478bd9Sstevel@tonic-gate 				/*
9647c478bd9Sstevel@tonic-gate 				 * an explicit instance number was given
9657c478bd9Sstevel@tonic-gate 				 * in the source.  so only consider this
9667c478bd9Sstevel@tonic-gate 				 * a configuration match if the number
9677c478bd9Sstevel@tonic-gate 				 * also matches.
9687c478bd9Sstevel@tonic-gate 				 */
9697c478bd9Sstevel@tonic-gate 				if (cp_num != np->u.name.child->u.ull)
9707c478bd9Sstevel@tonic-gate 					continue;
9717c478bd9Sstevel@tonic-gate 
972b5016cbbSstephh 			} else if (np->u.name.it != IT_HORIZONTAL) {
9737c478bd9Sstevel@tonic-gate 				struct iterinfo *iterinfop;
9747c478bd9Sstevel@tonic-gate 				const char *iters;
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 				/*
9777c478bd9Sstevel@tonic-gate 				 * vertical iterator.  look it up in
9787c478bd9Sstevel@tonic-gate 				 * the appropriate lut and if we get
9797c478bd9Sstevel@tonic-gate 				 * back a value it is either one that we
9807c478bd9Sstevel@tonic-gate 				 * set earlier, in which case we record
9817c478bd9Sstevel@tonic-gate 				 * the new value for this iteration and
9827c478bd9Sstevel@tonic-gate 				 * keep matching, or it is one that was
9837c478bd9Sstevel@tonic-gate 				 * set by an earlier reference to the
9847c478bd9Sstevel@tonic-gate 				 * iterator, in which case we only consider
9857c478bd9Sstevel@tonic-gate 				 * this a configuration match if the number
9867c478bd9Sstevel@tonic-gate 				 * matches cp_num.
9877c478bd9Sstevel@tonic-gate 				 */
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 				ASSERT(np->u.name.child != NULL);
9907c478bd9Sstevel@tonic-gate 				ASSERT(np->u.name.child->t == T_NAME);
9917c478bd9Sstevel@tonic-gate 				iters = np->u.name.child->u.name.s;
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 				if ((iterinfop = lut_lookup(infop->ex,
9947c478bd9Sstevel@tonic-gate 				    (void *)iters, NULL)) == NULL) {
9957c478bd9Sstevel@tonic-gate 					/* we're the first use, record our np */
9967c478bd9Sstevel@tonic-gate 					infop->ex = lut_add(infop->ex,
9977c478bd9Sstevel@tonic-gate 					    (void *)iters,
9987c478bd9Sstevel@tonic-gate 					    newiterinfo(cp_num, np), NULL);
9997c478bd9Sstevel@tonic-gate 				} else if (np == iterinfop->np) {
10007c478bd9Sstevel@tonic-gate 					/*
10017c478bd9Sstevel@tonic-gate 					 * we're the first use, back again
10027c478bd9Sstevel@tonic-gate 					 * for another iteration.  so update
10037c478bd9Sstevel@tonic-gate 					 * the num bound to this iterator in
10047c478bd9Sstevel@tonic-gate 					 * the lut.
10057c478bd9Sstevel@tonic-gate 					 */
10067c478bd9Sstevel@tonic-gate 					iterinfop->num = cp_num;
10077c478bd9Sstevel@tonic-gate 				} else if (cp_num != iterinfop->num) {
10087c478bd9Sstevel@tonic-gate 					/*
10097c478bd9Sstevel@tonic-gate 					 * an earlier reference to this
10107c478bd9Sstevel@tonic-gate 					 * iterator bound it to a different
10117c478bd9Sstevel@tonic-gate 					 * instance number, so there's no
10127c478bd9Sstevel@tonic-gate 					 * match here after all.
10133e8d8e18Sdb35262 					 *
10143e8d8e18Sdb35262 					 * however, it's possible that this
10153e8d8e18Sdb35262 					 * component should really be part of
10163e8d8e18Sdb35262 					 * the wildcard.  we explore this by
10173e8d8e18Sdb35262 					 * forcing this component into the
10183e8d8e18Sdb35262 					 * wildcarded section.
10193e8d8e18Sdb35262 					 *
10203e8d8e18Sdb35262 					 * for an more details of what's
10213e8d8e18Sdb35262 					 * going to happen now, see
10223e8d8e18Sdb35262 					 * comments block below entitled
10233e8d8e18Sdb35262 					 * "forcing components into
10243e8d8e18Sdb35262 					 * wildcard path".
10257c478bd9Sstevel@tonic-gate 					 */
1026b5016cbbSstephh 					if (np == wcp->nptop->u.event.epname)
1027b5016cbbSstephh 						vmatch_event(infop,
1028b5016cbbSstephh 						    config_child(cp), np, lnp,
1029b5016cbbSstephh 						    anp, wcp);
10307c478bd9Sstevel@tonic-gate 					continue;
10317c478bd9Sstevel@tonic-gate 				}
10327c478bd9Sstevel@tonic-gate 			}
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 			/*
1035b5016cbbSstephh 			 * if this was an IT_HORIZONTAL name, hmatch() will
1036b5016cbbSstephh 			 * expand all matches horizontally into a list.
10377c478bd9Sstevel@tonic-gate 			 * we know the list will contain at least
10387c478bd9Sstevel@tonic-gate 			 * one element (the one we just matched),
1039b5016cbbSstephh 			 * so we just let hmatch_event() do the rest.
10407c478bd9Sstevel@tonic-gate 			 *
1041b5016cbbSstephh 			 * recurse on to next component. Note that
10427c478bd9Sstevel@tonic-gate 			 * wildcarding is now turned off.
10437c478bd9Sstevel@tonic-gate 			 */
1044b5016cbbSstephh 			np->u.name.cp = cp;
10457c478bd9Sstevel@tonic-gate 			vmatch_event(infop, config_child(cp), np->u.name.next,
1046b5016cbbSstephh 			    lnp, anp, wcp);
1047b5016cbbSstephh 			np->u.name.cp = NULL;
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 			/*
1050*26733bfeSStephen Hanson 			 * handle case where this is the first section of the
1051*26733bfeSStephen Hanson 			 * path name and it is horizontally expanded.
1052*26733bfeSStephen Hanson 			 * In this case we want all matching nodes in the config
1053*26733bfeSStephen Hanson 			 * to be expanded horizontally - so set got_wc_hz and
1054*26733bfeSStephen Hanson 			 * leave all further processing to hmatch.
1055*26733bfeSStephen Hanson 			 */
1056*26733bfeSStephen Hanson 			if (G.matched && np == wcp->nptop->u.event.epname &&
1057*26733bfeSStephen Hanson 			    np->u.name.it == IT_HORIZONTAL)
1058*26733bfeSStephen Hanson 				wcp->got_wc_hz = 1;
1059*26733bfeSStephen Hanson 
1060*26733bfeSStephen Hanson 			/*
10613e8d8e18Sdb35262 			 * forcing components into wildcard path:
10623e8d8e18Sdb35262 			 *
10633e8d8e18Sdb35262 			 * if this component is the first match, force it
10643e8d8e18Sdb35262 			 * to be part of the wildcarded path and see if we
1065b5016cbbSstephh 			 * can get additional matches.
10663e8d8e18Sdb35262 			 *
10673e8d8e18Sdb35262 			 * here's an example.  suppose we have the
10683e8d8e18Sdb35262 			 * definition
10693e8d8e18Sdb35262 			 *	event foo@x/y
10703e8d8e18Sdb35262 			 * and configuration
10713e8d8e18Sdb35262 			 *	a0/x0/y0/a1/x1/y1
10723e8d8e18Sdb35262 			 *
10733e8d8e18Sdb35262 			 * the code up to this point will treat "a0" as the
10743e8d8e18Sdb35262 			 * wildcarded part of the path and "x0/y0" as the
10753e8d8e18Sdb35262 			 * nonwildcarded part, resulting in the instanced
10763e8d8e18Sdb35262 			 * event
10773e8d8e18Sdb35262 			 *	foo@a0/x0/y0
10783e8d8e18Sdb35262 			 *
10793e8d8e18Sdb35262 			 * in order to discover the next match (.../x1/y1)
10803e8d8e18Sdb35262 			 * in the configuration we have to force "x0" into
1081b5016cbbSstephh 			 * the wildcarded part of the path.
10823e8d8e18Sdb35262 			 * by doing so, we discover the wildcarded part
10833e8d8e18Sdb35262 			 * "a0/x0/y0/a1" and the nonwildcarded part "x1/y1"
10843e8d8e18Sdb35262 			 *
10853e8d8e18Sdb35262 			 * the following call to vmatch_event() is also
10863e8d8e18Sdb35262 			 * needed to properly handle the configuration
10873e8d8e18Sdb35262 			 *	b0/x0/b1/x1/y1
10883e8d8e18Sdb35262 			 *
10893e8d8e18Sdb35262 			 * the recursions into vmatch_event() will start
10903e8d8e18Sdb35262 			 * off uncovering "b0" as the wildcarded part and
10913e8d8e18Sdb35262 			 * "x0" as the start of the nonwildcarded path.
10923e8d8e18Sdb35262 			 * however, the next recursion will not result in a
10933e8d8e18Sdb35262 			 * match since there is no "y" following "x0".  the
10943e8d8e18Sdb35262 			 * subsequent match of (wildcard = "b0/x0/b1" and
10953e8d8e18Sdb35262 			 * nonwildcard = "x1/y1") will be discovered only
10963e8d8e18Sdb35262 			 * if "x0" is forced to be a part of the wildcarded
10973e8d8e18Sdb35262 			 * path.
10987c478bd9Sstevel@tonic-gate 			 */
1099b5016cbbSstephh 			if (np == wcp->nptop->u.event.epname)
1100b5016cbbSstephh 				vmatch_event(infop, config_child(cp), np, lnp,
1101b5016cbbSstephh 				    anp, wcp);
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 			if (np->u.name.it == IT_HORIZONTAL) {
11047c478bd9Sstevel@tonic-gate 				/*
11057c478bd9Sstevel@tonic-gate 				 * hmatch() finished iterating through
11067c478bd9Sstevel@tonic-gate 				 * the configuration as described above, so
11077c478bd9Sstevel@tonic-gate 				 * don't continue iterating here.
11087c478bd9Sstevel@tonic-gate 				 */
11097c478bd9Sstevel@tonic-gate 				return;
11107c478bd9Sstevel@tonic-gate 			}
1111b5016cbbSstephh 		} else if (np == wcp->nptop->u.event.epname) {
11127c478bd9Sstevel@tonic-gate 			/*
1113b5016cbbSstephh 			 * no match - carry on down the tree looking for
1114b5016cbbSstephh 			 * wildcarding
11157c478bd9Sstevel@tonic-gate 			 */
11167c478bd9Sstevel@tonic-gate 			vmatch_event(infop, config_child(cp), np, lnp, anp,
1117b5016cbbSstephh 			    wcp);
11187c478bd9Sstevel@tonic-gate 		}
11197c478bd9Sstevel@tonic-gate 	}
11207c478bd9Sstevel@tonic-gate }
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate /*
11237c478bd9Sstevel@tonic-gate  * vmatch -- find the next vertical expansion match in the config database
11247c478bd9Sstevel@tonic-gate  *
11257c478bd9Sstevel@tonic-gate  * this routine is called with three node pointers:
11267c478bd9Sstevel@tonic-gate  *	 np -- the parse we're matching
11277c478bd9Sstevel@tonic-gate  *	lnp -- the rest of the list we're currently working on
11287c478bd9Sstevel@tonic-gate  *	anp -- the rest of the arrow we're currently working on
11297c478bd9Sstevel@tonic-gate  *
11307c478bd9Sstevel@tonic-gate  * the expansion matching happens via three types of recursion:
11317c478bd9Sstevel@tonic-gate  *
11327c478bd9Sstevel@tonic-gate  *	- when given an arrow, handle the left-side and then recursively
11337c478bd9Sstevel@tonic-gate  *	  handle the right side (which might be another cascaded arrow).
11347c478bd9Sstevel@tonic-gate  *
11357c478bd9Sstevel@tonic-gate  *	- when handling one side of an arrow, recurse through the T_LIST
11367c478bd9Sstevel@tonic-gate  *	  to get to each event (or just move on to the event if there
11377c478bd9Sstevel@tonic-gate  *	  is a single event instead of a list)  since the arrow parse
11387c478bd9Sstevel@tonic-gate  *	  trees recurse left, we actually start with the right-most
11397c478bd9Sstevel@tonic-gate  *	  event list in the prop statement and work our way towards
11407c478bd9Sstevel@tonic-gate  *	  the left-most event list.
11417c478bd9Sstevel@tonic-gate  *
11427c478bd9Sstevel@tonic-gate  *	- when handling an event, recurse down each component of the
11437c478bd9Sstevel@tonic-gate  *	  pathname, matching in the config database and recording the
11447c478bd9Sstevel@tonic-gate  *	  matches in the explicit iterator dictionary as we go.
11457c478bd9Sstevel@tonic-gate  *
11467c478bd9Sstevel@tonic-gate  * when the bottom of this matching recursion is met, meaning we have
11477c478bd9Sstevel@tonic-gate  * set the "cp" pointers on all the names in the entire statement,
11487c478bd9Sstevel@tonic-gate  * we call hmatch() which does it's own recursion to handle horizontal
11497c478bd9Sstevel@tonic-gate  * expandsion and then call generate() to generate nodes, bubbles, and
11507c478bd9Sstevel@tonic-gate  * arrows in the instance tree.  generate() looks at the cp pointers to
11517c478bd9Sstevel@tonic-gate  * see what instance numbers were matched in the configuration database.
11527c478bd9Sstevel@tonic-gate  *
11537c478bd9Sstevel@tonic-gate  * when horizontal expansion appears, vmatch() finds only the first match
11547c478bd9Sstevel@tonic-gate  * and hmatch() then takes the horizontal expansion through all the other
11557c478bd9Sstevel@tonic-gate  * matches when generating the arrows in the instance tree.
11567c478bd9Sstevel@tonic-gate  *
11577c478bd9Sstevel@tonic-gate  * the "infop" passed down through the recursion contains a dictionary
11587c478bd9Sstevel@tonic-gate  * of the explicit iterators (all the implicit iterators have been converted
11597c478bd9Sstevel@tonic-gate  * to explicit iterators when the parse tree was created by tree.c), which
11607c478bd9Sstevel@tonic-gate  * allows things like this to work correctly:
11617c478bd9Sstevel@tonic-gate  *
11627c478bd9Sstevel@tonic-gate  *	prop error.a@x[n]/y/z -> error.b@x/y[n]/z -> error.c@x/y/z[n];
11637c478bd9Sstevel@tonic-gate  *
11647c478bd9Sstevel@tonic-gate  * during the top level call, the explicit iterator "n" will match an
11657c478bd9Sstevel@tonic-gate  * instance number in the config database, and the result will be recorded
11667c478bd9Sstevel@tonic-gate  * in the explicit iterator dictionary and passed down via "infop".  so
11677c478bd9Sstevel@tonic-gate  * when the recursive call tries to match y[n] in the config database, it
11687c478bd9Sstevel@tonic-gate  * will only match the same instance number as x[n] did since the dictionary
11697c478bd9Sstevel@tonic-gate  * is consulted to see if "n" took on a value already.
11707c478bd9Sstevel@tonic-gate  *
11717c478bd9Sstevel@tonic-gate  * at any point during the recursion, match*() can return to indicate
11727c478bd9Sstevel@tonic-gate  * a match was not found in the config database and that the caller should
11737c478bd9Sstevel@tonic-gate  * move on to the next potential match, if any.
11747c478bd9Sstevel@tonic-gate  *
11757c478bd9Sstevel@tonic-gate  * constraints are completely ignored by match(), so the statement:
11767c478bd9Sstevel@tonic-gate  *
11777c478bd9Sstevel@tonic-gate  *	prop error.a@x[n] -> error.b@x[n] {n != 0};
11787c478bd9Sstevel@tonic-gate  *
11797c478bd9Sstevel@tonic-gate  * might very well match x[0] if it appears in the config database.  it
11807c478bd9Sstevel@tonic-gate  * is the generate() routine that takes that match and then decides what
11817c478bd9Sstevel@tonic-gate  * arrow, if any, should be generated in the instance tree.  generate()
11827c478bd9Sstevel@tonic-gate  * looks at the explicit iterator dictionary to get values like "n" in
11837c478bd9Sstevel@tonic-gate  * the above example so that it can evaluate constraints.
11847c478bd9Sstevel@tonic-gate  *
11857c478bd9Sstevel@tonic-gate  */
11867c478bd9Sstevel@tonic-gate static void
vmatch(struct info * infop,struct node * np,struct node * lnp,struct node * anp)1187b5016cbbSstephh vmatch(struct info *infop, struct node *np, struct node *lnp, struct node *anp)
11887c478bd9Sstevel@tonic-gate {
1189b5016cbbSstephh 	struct node *np1, *np2, *oldepname, *oldnptop;
1190b5016cbbSstephh 	int epmatches;
1191b5016cbbSstephh 	struct config *cp;
1192b5016cbbSstephh 	struct wildcardinfo *wcp;
1193b5016cbbSstephh 
11947c478bd9Sstevel@tonic-gate 	if (np == NULL) {
1195b7d3956bSstephh 		G.matched = 1;
11967c478bd9Sstevel@tonic-gate 		if (lnp)
1197b5016cbbSstephh 			vmatch(infop, lnp, NULL, anp);
11987c478bd9Sstevel@tonic-gate 		else if (anp)
1199b5016cbbSstephh 			vmatch(infop, anp, NULL, NULL);
12007c478bd9Sstevel@tonic-gate 		else {
12017c478bd9Sstevel@tonic-gate 			struct node *src;
12027c478bd9Sstevel@tonic-gate 			struct node *dst;
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 			/* end of vertical match recursion */
12057c478bd9Sstevel@tonic-gate 			outfl(O_ALTFP|O_VERB3|O_NONL,
12067c478bd9Sstevel@tonic-gate 			    infop->anp->file, infop->anp->line, "vmatch: ");
12077c478bd9Sstevel@tonic-gate 			ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, infop->anp);
12087c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3, NULL);
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 			generate_nork(
12117c478bd9Sstevel@tonic-gate 			    itree_np2nork(infop->anp->u.arrow.nnp),
12127c478bd9Sstevel@tonic-gate 			    itree_np2nork(infop->anp->u.arrow.knp));
12137c478bd9Sstevel@tonic-gate 			dst = infop->anp->u.arrow.rhs;
12147c478bd9Sstevel@tonic-gate 			src = infop->anp->u.arrow.lhs;
12157c478bd9Sstevel@tonic-gate 			for (;;) {
12167c478bd9Sstevel@tonic-gate 				generate_new();	/* new set of arrows */
12177c478bd9Sstevel@tonic-gate 				if (src->t == T_ARROW) {
12187c478bd9Sstevel@tonic-gate 					hmatch(infop, src->u.arrow.rhs, dst);
12197c478bd9Sstevel@tonic-gate 					generate_nork(
12207c478bd9Sstevel@tonic-gate 					    itree_np2nork(src->u.arrow.nnp),
12217c478bd9Sstevel@tonic-gate 					    itree_np2nork(src->u.arrow.knp));
12227c478bd9Sstevel@tonic-gate 					dst = src->u.arrow.rhs;
12237c478bd9Sstevel@tonic-gate 					src = src->u.arrow.lhs;
12247c478bd9Sstevel@tonic-gate 				} else {
12257c478bd9Sstevel@tonic-gate 					hmatch(infop, src, dst);
12267c478bd9Sstevel@tonic-gate 					break;
12277c478bd9Sstevel@tonic-gate 				}
12287c478bd9Sstevel@tonic-gate 			}
12297c478bd9Sstevel@tonic-gate 		}
12307c478bd9Sstevel@tonic-gate 		return;
12317c478bd9Sstevel@tonic-gate 	}
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	switch (np->t) {
12347c478bd9Sstevel@tonic-gate 	case T_EVENT: {
1235b5016cbbSstephh 		epmatches = 0;
1236b5016cbbSstephh 		/*
1237b5016cbbSstephh 		 * see if we already have a match in the wcps
1238b5016cbbSstephh 		 */
1239b5016cbbSstephh 		for (wcp = wcproot; wcp; wcp = wcp->next) {
1240b5016cbbSstephh 			oldepname = wcp->oldepname;
1241b5016cbbSstephh 			oldnptop = wcp->nptop;
1242b5016cbbSstephh 			for (np1 = oldepname, np2 = np->u.event.epname;
1243b5016cbbSstephh 			    np1 != NULL && np2 != NULL; np1 = np1->u.name.next,
1244b5016cbbSstephh 			    np2 = np2->u.name.next) {
1245b5016cbbSstephh 				if (strcmp(np1->u.name.s, np2->u.name.s) != 0)
1246b5016cbbSstephh 					break;
1247b5016cbbSstephh 				if (np1->u.name.child->t !=
1248b5016cbbSstephh 				    np2->u.name.child->t)
1249b5016cbbSstephh 					break;
1250b5016cbbSstephh 				if (np1->u.name.child->t == T_NUM &&
1251b5016cbbSstephh 				    np1->u.name.child->u.ull !=
1252b5016cbbSstephh 				    np2->u.name.child->u.ull)
1253b5016cbbSstephh 					break;
1254b5016cbbSstephh 				if (np1->u.name.child->t == T_NAME &&
1255b5016cbbSstephh 				    strcmp(np1->u.name.child->u.name.s,
1256b5016cbbSstephh 				    np2->u.name.child->u.name.s) != 0)
1257b5016cbbSstephh 					break;
1258b5016cbbSstephh 				epmatches++;
1259b5016cbbSstephh 			}
1260b5016cbbSstephh 			if (epmatches)
1261b5016cbbSstephh 				break;
1262b5016cbbSstephh 		}
1263b5016cbbSstephh 		if (epmatches && np1 == NULL && np2 == NULL) {
1264b5016cbbSstephh 			/*
1265b5016cbbSstephh 			 * complete names match, can just borrow the fields
1266b5016cbbSstephh 			 */
1267b5016cbbSstephh 			oldepname = np->u.event.epname;
1268b5016cbbSstephh 			np->u.event.epname = oldnptop->u.event.epname;
1269b5016cbbSstephh 			np->u.event.oldepname = wcp->oldepname;
1270b5016cbbSstephh 			np->u.event.ewname = wcp->ewname;
1271b5016cbbSstephh 			vmatch(infop, NULL, lnp, anp);
1272b5016cbbSstephh 			np->u.event.epname = oldepname;
1273b5016cbbSstephh 			return;
1274b5016cbbSstephh 		}
1275b7d3956bSstephh 		G.matched = 0;
1276b5016cbbSstephh 		if (epmatches) {
1277b5016cbbSstephh 			/*
1278b5016cbbSstephh 			 * just first part of names match - do wildcarding
1279b5016cbbSstephh 			 * by using existing wcp including ewname and also
1280b5016cbbSstephh 			 * copying as much of pwname as is valid, then start
1281b5016cbbSstephh 			 * vmatch_event() at start of non-matching section
1282b5016cbbSstephh 			 */
1283b5016cbbSstephh 			for (np1 = oldepname, np2 = np->u.event.epname;
1284b5016cbbSstephh 			    epmatches != 0; epmatches--) {
1285b5016cbbSstephh 				cp = np1->u.name.cp;
1286b5016cbbSstephh 				np2->u.name.cp = cp;
1287b5016cbbSstephh 				np1 = np1->u.name.next;
1288b5016cbbSstephh 				np2 = np2->u.name.next;
1289b5016cbbSstephh 			}
1290b5016cbbSstephh 			wcp->oldepname = np->u.event.epname;
1291b5016cbbSstephh 			wcp->nptop = np;
1292b5016cbbSstephh 			vmatch_event(infop, config_child(cp), np2, lnp,
1293b5016cbbSstephh 			    anp, wcp);
1294b5016cbbSstephh 			wcp->oldepname = oldepname;
1295b5016cbbSstephh 			wcp->nptop = oldnptop;
1296b7d3956bSstephh 			if (G.matched == 0) {
1297b7d3956bSstephh 				/*
1298b7d3956bSstephh 				 * This list entry is NULL. Move on to next item
1299b7d3956bSstephh 				 * in the list.
1300b7d3956bSstephh 				 */
1301b7d3956bSstephh 				vmatch(infop, NULL, lnp, anp);
1302b7d3956bSstephh 			}
1303b5016cbbSstephh 			return;
1304b5016cbbSstephh 		}
1305b5016cbbSstephh 		/*
1306b5016cbbSstephh 		 * names do not match - allocate a new wcp
1307b5016cbbSstephh 		 */
1308b5016cbbSstephh 		wcp = MALLOC(sizeof (struct wildcardinfo));
1309b5016cbbSstephh 		wcp->next = wcproot;
1310b5016cbbSstephh 		wcproot = wcp;
1311b5016cbbSstephh 		wcp->nptop = np;
1312b5016cbbSstephh 		wcp->oldepname = np->u.event.epname;
1313b5016cbbSstephh 		wcp->ewname = NULL;
1314*26733bfeSStephen Hanson 		wcp->got_wc_hz = 0;
1315b5016cbbSstephh 
13163e8d8e18Sdb35262 		vmatch_event(infop, config_child(infop->croot),
1317b5016cbbSstephh 		    np->u.event.epname, lnp, anp, wcp);
1318b5016cbbSstephh 
1319b5016cbbSstephh 		wcproot = wcp->next;
1320b5016cbbSstephh 		FREE(wcp);
1321b7d3956bSstephh 		if (G.matched == 0) {
1322b7d3956bSstephh 			/*
1323b7d3956bSstephh 			 * This list entry is NULL. Move on to next item in the
1324b7d3956bSstephh 			 * list.
1325b7d3956bSstephh 			 */
1326b7d3956bSstephh 			vmatch(infop, NULL, lnp, anp);
1327b7d3956bSstephh 		}
13287c478bd9Sstevel@tonic-gate 		break;
13297c478bd9Sstevel@tonic-gate 	}
13307c478bd9Sstevel@tonic-gate 	case T_LIST:
13317c478bd9Sstevel@tonic-gate 		ASSERT(lnp == NULL);
1332b5016cbbSstephh 		vmatch(infop, np->u.expr.right, np->u.expr.left, anp);
13337c478bd9Sstevel@tonic-gate 		break;
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	case T_ARROW:
13367c478bd9Sstevel@tonic-gate 		ASSERT(lnp == NULL && anp == NULL);
1337b7d3956bSstephh 		vmatch(infop, np->u.arrow.rhs, NULL, np->u.arrow.parent);
13387c478bd9Sstevel@tonic-gate 		break;
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	default:
13417c478bd9Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
13427c478bd9Sstevel@tonic-gate 		    "vmatch: unexpected type: %s",
13437c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
13447c478bd9Sstevel@tonic-gate 	}
13457c478bd9Sstevel@tonic-gate }
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate static void
find_first_arrow(struct info * infop,struct node * anp)1348b7d3956bSstephh find_first_arrow(struct info *infop, struct node *anp)
1349b7d3956bSstephh {
1350b7d3956bSstephh 	if (anp->u.arrow.lhs->t == T_ARROW) {
1351b7d3956bSstephh 		anp->u.arrow.lhs->u.arrow.parent = anp;
1352b7d3956bSstephh 		find_first_arrow(infop, anp->u.arrow.lhs);
1353b7d3956bSstephh 	} else
1354b7d3956bSstephh 		vmatch(infop, anp->u.arrow.lhs, NULL, anp);
1355b7d3956bSstephh }
1356b7d3956bSstephh 
1357b7d3956bSstephh static void
cp_reset(struct node * np)13587c478bd9Sstevel@tonic-gate cp_reset(struct node *np)
13597c478bd9Sstevel@tonic-gate {
13607c478bd9Sstevel@tonic-gate 	if (np == NULL)
13617c478bd9Sstevel@tonic-gate 		return;
13627c478bd9Sstevel@tonic-gate 	switch (np->t) {
13637c478bd9Sstevel@tonic-gate 	case T_NAME:
13647c478bd9Sstevel@tonic-gate 		np->u.name.cp = NULL;
13657c478bd9Sstevel@tonic-gate 		cp_reset(np->u.name.next);
13667c478bd9Sstevel@tonic-gate 		break;
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	case T_LIST:
13697c478bd9Sstevel@tonic-gate 		cp_reset(np->u.expr.left);
13707c478bd9Sstevel@tonic-gate 		cp_reset(np->u.expr.right);
13717c478bd9Sstevel@tonic-gate 		break;
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 	case T_ARROW:
13747c478bd9Sstevel@tonic-gate 		cp_reset(np->u.arrow.lhs);
13757c478bd9Sstevel@tonic-gate 		cp_reset(np->u.arrow.rhs);
13767c478bd9Sstevel@tonic-gate 		break;
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	case T_EVENT:
13797c478bd9Sstevel@tonic-gate 		cp_reset(np->u.event.epname);
13807c478bd9Sstevel@tonic-gate 		break;
13817c478bd9Sstevel@tonic-gate 	}
13827c478bd9Sstevel@tonic-gate }
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate /*
13857c478bd9Sstevel@tonic-gate  * itree_create -- apply the current config to the current parse tree
13867c478bd9Sstevel@tonic-gate  *
13877c478bd9Sstevel@tonic-gate  * returns a lut mapping fully-instance-qualified names to struct events.
13887c478bd9Sstevel@tonic-gate  *
13897c478bd9Sstevel@tonic-gate  */
13907c478bd9Sstevel@tonic-gate struct lut *
itree_create(struct config * croot)13917c478bd9Sstevel@tonic-gate itree_create(struct config *croot)
13927c478bd9Sstevel@tonic-gate {
13937c478bd9Sstevel@tonic-gate 	struct lut *retval;
13947c478bd9Sstevel@tonic-gate 	struct node *propnp;
1395b5016cbbSstephh 	extern int alloc_total();
1396b5016cbbSstephh 	int init_size;
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	Ninfo.lut = NULL;
13997c478bd9Sstevel@tonic-gate 	Ninfo.croot = croot;
1400b5016cbbSstephh 	init_size = alloc_total();
1401b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size);
14027c478bd9Sstevel@tonic-gate 	for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
14037c478bd9Sstevel@tonic-gate 		struct node *anp = propnp->u.stmt.np;
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 		ASSERTeq(anp->t, T_ARROW, ptree_nodetype2str);
14067c478bd9Sstevel@tonic-gate 
1407b5016cbbSstephh 		if (!anp->u.arrow.needed)
1408b5016cbbSstephh 			continue;
14097c478bd9Sstevel@tonic-gate 		Ninfo.anp = anp;
14107c478bd9Sstevel@tonic-gate 		Ninfo.ex = NULL;
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate 		generate_arrownp(anp);
1413b7d3956bSstephh 		anp->u.arrow.parent = NULL;
1414b7d3956bSstephh 		find_first_arrow(&Ninfo, anp);
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 		if (Ninfo.ex) {
14177c478bd9Sstevel@tonic-gate 			lut_free(Ninfo.ex, iterinfo_destructor, NULL);
14187c478bd9Sstevel@tonic-gate 			Ninfo.ex = NULL;
14197c478bd9Sstevel@tonic-gate 		}
14207c478bd9Sstevel@tonic-gate 		cp_reset(anp);
14217c478bd9Sstevel@tonic-gate 	}
14227c478bd9Sstevel@tonic-gate 
1423b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "itree_create added %d bytes",
1424b5016cbbSstephh 	    alloc_total() - init_size);
14257c478bd9Sstevel@tonic-gate 	retval = Ninfo.lut;
14267c478bd9Sstevel@tonic-gate 	Ninfo.lut = NULL;
14277c478bd9Sstevel@tonic-gate 	return (retval);
14287c478bd9Sstevel@tonic-gate }
14297c478bd9Sstevel@tonic-gate 
1430b5016cbbSstephh /*
1431b5016cbbSstephh  * initial first pass of the rules.
1432b5016cbbSstephh  * We don't use the config at all. Just check the last part of the pathname
1433b5016cbbSstephh  * in the rules. If this matches the last part of the pathname in the first
1434b5016cbbSstephh  * ereport, then set pathname to the pathname in the ereport. If not then
1435b5016cbbSstephh  * set pathname to just the last part of pathname with instance number 0.
1436b5016cbbSstephh  * Constraints are ignored and all nork values are set to 0. If after all that
1437b5016cbbSstephh  * any rules can still not be associated with the ereport, then they are set
1438b5016cbbSstephh  * to not needed in prune_propagations() and ignored in the real itree_create()
1439b5016cbbSstephh  * which follows.
1440b5016cbbSstephh  */
1441b5016cbbSstephh 
1442b5016cbbSstephh static struct event *
add_event_dummy(struct node * np,const struct ipath * ipp)1443b5016cbbSstephh add_event_dummy(struct node *np, const struct ipath *ipp)
1444b5016cbbSstephh {
1445b5016cbbSstephh 	struct event *ret;
1446b5016cbbSstephh 	struct event searchevent;	/* just used for searching */
1447b5016cbbSstephh 	extern struct ipath *ipath_dummy(struct node *, struct ipath *);
14486e1fa242SStephen Hanson 	struct ipath *ipp_un;
14496e1fa242SStephen Hanson 	extern struct ipath *ipath_for_usednames(struct node *);
1450b5016cbbSstephh 
1451b5016cbbSstephh 	searchevent.enode = np;
1452b5016cbbSstephh 	searchevent.ipp = ipath_dummy(np->u.event.epname, (struct ipath *)ipp);
14536e1fa242SStephen Hanson 	ipp_un = ipath_for_usednames(np->u.event.epname);
1454b5016cbbSstephh 	if ((ret = lut_lookup(Ninfo.lut, (void *)&searchevent,
1455b5016cbbSstephh 	    (lut_cmp)event_cmp)) != NULL)
1456b5016cbbSstephh 		return (ret);
1457b5016cbbSstephh 
1458b5016cbbSstephh 	ret = alloc_xmalloc(sizeof (*ret));
1459b5016cbbSstephh 	bzero(ret, sizeof (*ret));
1460b5016cbbSstephh 	ret->t = np->u.event.ename->u.name.t;
1461b5016cbbSstephh 	ret->enode = np;
1462b5016cbbSstephh 	ret->ipp = searchevent.ipp;
14636e1fa242SStephen Hanson 	ret->ipp_un = ipp_un;
1464b5016cbbSstephh 	Ninfo.lut = lut_add(Ninfo.lut, (void *)ret, (void *)ret,
1465b5016cbbSstephh 	    (lut_cmp)event_cmp);
1466b5016cbbSstephh 	return (ret);
1467b5016cbbSstephh }
1468b5016cbbSstephh 
1469b5016cbbSstephh /*ARGSUSED*/
1470b5016cbbSstephh struct lut *
itree_create_dummy(const char * e0class,const struct ipath * e0ipp)1471b5016cbbSstephh itree_create_dummy(const char *e0class, const struct ipath *e0ipp)
1472b5016cbbSstephh {
1473b5016cbbSstephh 	struct node *propnp;
1474b5016cbbSstephh 	struct event *frome, *toe;
1475b5016cbbSstephh 	struct bubble *frombp, *tobp;
1476b5016cbbSstephh 	struct arrow *arrowp;
1477b5016cbbSstephh 	struct node *src, *dst, *slst, *dlst, *arrownp, *oldarrownp;
1478b5016cbbSstephh 	int gen = 0;
1479b5016cbbSstephh 	extern int alloc_total();
1480b5016cbbSstephh 	int init_size;
1481b5016cbbSstephh 
1482b5016cbbSstephh 	Ninfo.lut = NULL;
1483b5016cbbSstephh 	init_size = alloc_total();
1484b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size);
1485b5016cbbSstephh 	for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
1486b5016cbbSstephh 		arrownp = propnp->u.stmt.np;
1487b5016cbbSstephh 		while (arrownp) {
1488b5016cbbSstephh 			gen++;
1489b5016cbbSstephh 			dlst = arrownp->u.arrow.rhs;
1490b5016cbbSstephh 			slst = arrownp->u.arrow.lhs;
1491b5016cbbSstephh 			oldarrownp = arrownp;
1492b5016cbbSstephh 			if (slst->t == T_ARROW) {
1493b5016cbbSstephh 				arrownp = slst;
1494b5016cbbSstephh 				slst = slst->u.arrow.rhs;
1495b5016cbbSstephh 			} else {
1496b5016cbbSstephh 				arrownp = NULL;
1497b5016cbbSstephh 			}
1498b5016cbbSstephh 			while (slst) {
1499b5016cbbSstephh 				if (slst->t == T_LIST) {
1500b5016cbbSstephh 					src = slst->u.expr.right;
1501b5016cbbSstephh 					slst = slst->u.expr.left;
1502b5016cbbSstephh 				} else {
1503b5016cbbSstephh 					src = slst;
1504b5016cbbSstephh 					slst = NULL;
1505b5016cbbSstephh 				}
1506b5016cbbSstephh 				frome = add_event_dummy(src, e0ipp);
1507b5016cbbSstephh 				frombp = itree_add_bubble(frome, B_FROM, 0, 0);
1508b5016cbbSstephh 				while (dlst) {
1509b5016cbbSstephh 					if (dlst->t == T_LIST) {
1510b5016cbbSstephh 						dst = dlst->u.expr.right;
1511b5016cbbSstephh 						dlst = dlst->u.expr.left;
1512b5016cbbSstephh 					} else {
1513b5016cbbSstephh 						dst = dlst;
1514b5016cbbSstephh 						dlst = NULL;
1515b5016cbbSstephh 					}
1516b5016cbbSstephh 					arrowp = alloc_xmalloc(
1517b5016cbbSstephh 					    sizeof (struct arrow));
1518b5016cbbSstephh 					bzero(arrowp, sizeof (struct arrow));
1519b5016cbbSstephh 					arrowp->pnode = oldarrownp;
1520b5016cbbSstephh 					toe = add_event_dummy(dst, e0ipp);
1521b5016cbbSstephh 					tobp = itree_add_bubble(toe, B_TO, 0,
1522b5016cbbSstephh 					    gen);
1523b5016cbbSstephh 					arrowp->tail = frombp;
1524b5016cbbSstephh 					arrowp->head = tobp;
1525b5016cbbSstephh 					add_arrow(frombp, arrowp);
1526b5016cbbSstephh 					add_arrow(tobp, arrowp);
1527b5016cbbSstephh 					arrow_add_within(arrowp,
1528b5016cbbSstephh 					    dst->u.event.declp->u.stmt.np->
1529b5016cbbSstephh 					    u.event.eexprlist);
1530b5016cbbSstephh 					arrow_add_within(arrowp,
1531b5016cbbSstephh 					    dst->u.event.eexprlist);
1532b5016cbbSstephh 				}
1533b5016cbbSstephh 			}
1534b5016cbbSstephh 		}
1535b5016cbbSstephh 	}
1536b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "itree_create added %d bytes",
1537b5016cbbSstephh 	    alloc_total() - init_size);
1538b5016cbbSstephh 	return (Ninfo.lut);
1539b5016cbbSstephh }
1540b5016cbbSstephh 
15417c478bd9Sstevel@tonic-gate void
itree_free(struct lut * lutp)15427c478bd9Sstevel@tonic-gate itree_free(struct lut *lutp)
15437c478bd9Sstevel@tonic-gate {
1544b5016cbbSstephh 	int init_size;
1545b5016cbbSstephh 
1546b5016cbbSstephh 	init_size = alloc_total();
1547b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "start itree_free");
15487c478bd9Sstevel@tonic-gate 	lut_free(lutp, itree_destructor, NULL);
1549b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "itree_free freed %d bytes",
1550b5016cbbSstephh 	    init_size - alloc_total());
15517c478bd9Sstevel@tonic-gate }
15527c478bd9Sstevel@tonic-gate 
155300d0963fSdilpreet void
itree_prune(struct lut * lutp)155400d0963fSdilpreet itree_prune(struct lut *lutp)
155500d0963fSdilpreet {
1556b5016cbbSstephh 	int init_size;
1557b5016cbbSstephh 
1558b5016cbbSstephh 	init_size = alloc_total();
1559b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "start itree_prune");
156000d0963fSdilpreet 	lut_walk(lutp, itree_pruner, NULL);
1561b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "itree_prune freed %d bytes",
1562b5016cbbSstephh 	    init_size - alloc_total());
15637c478bd9Sstevel@tonic-gate }
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate void
itree_pevent_brief(int flags,struct event * ep)15667c478bd9Sstevel@tonic-gate itree_pevent_brief(int flags, struct event *ep)
15677c478bd9Sstevel@tonic-gate {
15687c478bd9Sstevel@tonic-gate 	ASSERT(ep != NULL);
15697c478bd9Sstevel@tonic-gate 	ASSERT(ep->enode != NULL);
15707c478bd9Sstevel@tonic-gate 	ASSERT(ep->ipp != NULL);
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	ipath_print(flags, ep->enode->u.event.ename->u.name.s, ep->ipp);
15737c478bd9Sstevel@tonic-gate }
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15767c478bd9Sstevel@tonic-gate static void
itree_pevent(struct event * lhs,struct event * ep,void * arg)15777c478bd9Sstevel@tonic-gate itree_pevent(struct event *lhs, struct event *ep, void *arg)
15787c478bd9Sstevel@tonic-gate {
15797c478bd9Sstevel@tonic-gate 	struct plut_wlk_data propd;
15807c478bd9Sstevel@tonic-gate 	struct bubble *bp;
1581837416c3Scy152378 	int flags = (int)(intptr_t)arg;
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	itree_pevent_brief(flags, ep);
15847c478bd9Sstevel@tonic-gate 	if (ep->t == N_EREPORT)
15857c478bd9Sstevel@tonic-gate 		out(flags, " (count %d)", ep->count);
15867c478bd9Sstevel@tonic-gate 	else
15877c478bd9Sstevel@tonic-gate 		out(flags, NULL);
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	if (ep->props) {
15907c478bd9Sstevel@tonic-gate 		propd.flags = flags;
15917c478bd9Sstevel@tonic-gate 		propd.first = 1;
15927c478bd9Sstevel@tonic-gate 		out(flags, "Properties:");
15937c478bd9Sstevel@tonic-gate 		lut_walk(ep->props, ptree_plut, (void *)&propd);
15947c478bd9Sstevel@tonic-gate 	}
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
15977c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
15987c478bd9Sstevel@tonic-gate 		/* Print only TO bubbles in this loop */
15997c478bd9Sstevel@tonic-gate 		if (bp->t != B_TO)
16007c478bd9Sstevel@tonic-gate 			continue;
16017c478bd9Sstevel@tonic-gate 		itree_pbubble(flags, bp);
16027c478bd9Sstevel@tonic-gate 	}
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
16057c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
16067c478bd9Sstevel@tonic-gate 		/* Print only INHIBIT bubbles in this loop */
16077c478bd9Sstevel@tonic-gate 		if (bp->t != B_INHIBIT)
16087c478bd9Sstevel@tonic-gate 			continue;
16097c478bd9Sstevel@tonic-gate 		itree_pbubble(flags, bp);
16107c478bd9Sstevel@tonic-gate 	}
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
16137c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
16147c478bd9Sstevel@tonic-gate 		/* Print only FROM bubbles in this loop */
16157c478bd9Sstevel@tonic-gate 		if (bp->t != B_FROM)
16167c478bd9Sstevel@tonic-gate 			continue;
16177c478bd9Sstevel@tonic-gate 		itree_pbubble(flags, bp);
16187c478bd9Sstevel@tonic-gate 	}
16197c478bd9Sstevel@tonic-gate }
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate static void
itree_pbubble(int flags,struct bubble * bp)16227c478bd9Sstevel@tonic-gate itree_pbubble(int flags, struct bubble *bp)
16237c478bd9Sstevel@tonic-gate {
16247c478bd9Sstevel@tonic-gate 	struct constraintlist *cp;
16257c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 	ASSERT(bp != NULL);
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "   ");
16307c478bd9Sstevel@tonic-gate 	if (bp->mark)
16317c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, "*");
16327c478bd9Sstevel@tonic-gate 	else
16337c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, " ");
16347c478bd9Sstevel@tonic-gate 	if (bp->t == B_FROM)
16357c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, "N=%d to:", bp->nork);
16367c478bd9Sstevel@tonic-gate 	else if (bp->t == B_TO)
16377c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, "K=%d from:", bp->nork);
16387c478bd9Sstevel@tonic-gate 	else
16397c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, "K=%d masked from:", bp->nork);
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 	if (bp->t == B_TO || bp->t == B_INHIBIT) {
16427c478bd9Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
16437c478bd9Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
16447c478bd9Sstevel@tonic-gate 			ASSERT(ap->arrowp->head == bp);
16457c478bd9Sstevel@tonic-gate 			ASSERT(ap->arrowp->tail != NULL);
16467c478bd9Sstevel@tonic-gate 			ASSERT(ap->arrowp->tail->myevent != NULL);
16477c478bd9Sstevel@tonic-gate 			out(flags|O_NONL, " ");
16487c478bd9Sstevel@tonic-gate 			itree_pevent_brief(flags, ap->arrowp->tail->myevent);
16497c478bd9Sstevel@tonic-gate 		}
16507c478bd9Sstevel@tonic-gate 		out(flags, NULL);
16517c478bd9Sstevel@tonic-gate 		return;
16527c478bd9Sstevel@tonic-gate 	}
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	for (ap = itree_next_arrow(bp, NULL); ap;
16557c478bd9Sstevel@tonic-gate 	    ap = itree_next_arrow(bp, ap)) {
16567c478bd9Sstevel@tonic-gate 		ASSERT(ap->arrowp->tail == bp);
16577c478bd9Sstevel@tonic-gate 		ASSERT(ap->arrowp->head != NULL);
16587c478bd9Sstevel@tonic-gate 		ASSERT(ap->arrowp->head->myevent != NULL);
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, " ");
16617c478bd9Sstevel@tonic-gate 		itree_pevent_brief(flags, ap->arrowp->head->myevent);
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, " ");
16647c478bd9Sstevel@tonic-gate 		ptree_timeval(flags, &ap->arrowp->mindelay);
16657c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, ",");
16667c478bd9Sstevel@tonic-gate 		ptree_timeval(flags, &ap->arrowp->maxdelay);
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 		/* Display anything from the propogation node? */
16697c478bd9Sstevel@tonic-gate 		out(O_VERB3|O_NONL, " <%s:%d>",
16707c478bd9Sstevel@tonic-gate 		    ap->arrowp->pnode->file, ap->arrowp->pnode->line);
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 		if (itree_next_constraint(ap->arrowp, NULL))
16737c478bd9Sstevel@tonic-gate 			out(flags|O_NONL, " {");
16747c478bd9Sstevel@tonic-gate 
16757c478bd9Sstevel@tonic-gate 		for (cp = itree_next_constraint(ap->arrowp, NULL); cp;
16767c478bd9Sstevel@tonic-gate 		    cp = itree_next_constraint(ap->arrowp, cp)) {
16777c478bd9Sstevel@tonic-gate 			ptree(flags, cp->cnode, 1, 0);
16787c478bd9Sstevel@tonic-gate 			if (itree_next_constraint(ap->arrowp, cp))
16797c478bd9Sstevel@tonic-gate 				out(flags|O_NONL, ", ");
16807c478bd9Sstevel@tonic-gate 		}
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 		if (itree_next_constraint(ap->arrowp, NULL))
16837c478bd9Sstevel@tonic-gate 			out(flags|O_NONL, "}");
16847c478bd9Sstevel@tonic-gate 	}
16857c478bd9Sstevel@tonic-gate 	out(flags, NULL);
16867c478bd9Sstevel@tonic-gate }
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate void
itree_ptree(int flags,struct lut * itp)16897c478bd9Sstevel@tonic-gate itree_ptree(int flags, struct lut *itp)
16907c478bd9Sstevel@tonic-gate {
1691837416c3Scy152378 	lut_walk(itp, (lut_cb)itree_pevent, (void *)(intptr_t)flags);
16927c478bd9Sstevel@tonic-gate }
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16957c478bd9Sstevel@tonic-gate static void
itree_destructor(void * left,void * right,void * arg)16967c478bd9Sstevel@tonic-gate itree_destructor(void *left, void *right, void *arg)
16977c478bd9Sstevel@tonic-gate {
16987c478bd9Sstevel@tonic-gate 	struct event *ep = (struct event *)right;
16997c478bd9Sstevel@tonic-gate 	struct bubble *nextbub, *bub;
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	/* Free the properties */
170200d0963fSdilpreet 	if (ep->props)
17037c478bd9Sstevel@tonic-gate 		lut_free(ep->props, instances_destructor, NULL);
17047c478bd9Sstevel@tonic-gate 
17057aec1d6eScindi 	/* Free the payload properties */
170600d0963fSdilpreet 	if (ep->payloadprops)
17077aec1d6eScindi 		lut_free(ep->payloadprops, payloadprops_destructor, NULL);
17087aec1d6eScindi 
1709b7d3956bSstephh 	/* Free the serd properties */
1710b7d3956bSstephh 	if (ep->serdprops)
1711b7d3956bSstephh 		lut_free(ep->serdprops, serdprops_destructor, NULL);
1712b7d3956bSstephh 
17137c478bd9Sstevel@tonic-gate 	/* Free my bubbles */
17147c478bd9Sstevel@tonic-gate 	for (bub = ep->bubbles; bub != NULL; ) {
17157c478bd9Sstevel@tonic-gate 		nextbub = bub->next;
17167c478bd9Sstevel@tonic-gate 		/*
17177c478bd9Sstevel@tonic-gate 		 * Free arrows if they are FROM me.  Free arrowlists on
17187c478bd9Sstevel@tonic-gate 		 * other types of bubbles (but not the attached arrows,
17197c478bd9Sstevel@tonic-gate 		 * which will be freed when we free the originating
17207c478bd9Sstevel@tonic-gate 		 * bubble.
17217c478bd9Sstevel@tonic-gate 		 */
17227c478bd9Sstevel@tonic-gate 		if (bub->t == B_FROM)
17237c478bd9Sstevel@tonic-gate 			itree_free_arrowlists(bub, 1);
17247c478bd9Sstevel@tonic-gate 		else
17257c478bd9Sstevel@tonic-gate 			itree_free_arrowlists(bub, 0);
17267c478bd9Sstevel@tonic-gate 		itree_free_bubble(bub);
17277c478bd9Sstevel@tonic-gate 		bub = nextbub;
17287c478bd9Sstevel@tonic-gate 	}
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	nvlist_free(ep->nvp);
1731b5016cbbSstephh 	alloc_xfree(ep, sizeof (*ep));
17327c478bd9Sstevel@tonic-gate }
17337c478bd9Sstevel@tonic-gate 
173400d0963fSdilpreet /*ARGSUSED*/
173500d0963fSdilpreet static void
itree_pruner(void * left,void * right,void * arg)173600d0963fSdilpreet itree_pruner(void *left, void *right, void *arg)
173700d0963fSdilpreet {
173800d0963fSdilpreet 	struct event *ep = (struct event *)right;
173900d0963fSdilpreet 	struct bubble *nextbub, *bub;
174000d0963fSdilpreet 
174100d0963fSdilpreet 	if (ep->keep_in_tree)
174200d0963fSdilpreet 		return;
174300d0963fSdilpreet 
174400d0963fSdilpreet 	/* Free the properties */
174500d0963fSdilpreet 	lut_free(ep->props, instances_destructor, NULL);
174600d0963fSdilpreet 
174700d0963fSdilpreet 	/* Free the payload properties */
174800d0963fSdilpreet 	lut_free(ep->payloadprops, payloadprops_destructor, NULL);
174900d0963fSdilpreet 
1750b7d3956bSstephh 	/* Free the serd properties */
1751b7d3956bSstephh 	lut_free(ep->serdprops, serdprops_destructor, NULL);
1752b7d3956bSstephh 
175300d0963fSdilpreet 	/* Free my bubbles */
175400d0963fSdilpreet 	for (bub = ep->bubbles; bub != NULL; ) {
175500d0963fSdilpreet 		nextbub = bub->next;
175600d0963fSdilpreet 		itree_prune_arrowlists(bub);
175700d0963fSdilpreet 		itree_free_bubble(bub);
175800d0963fSdilpreet 		bub = nextbub;
175900d0963fSdilpreet 	}
176000d0963fSdilpreet 
176100d0963fSdilpreet 	nvlist_free(ep->nvp);
176200d0963fSdilpreet 	ep->props = NULL;
176300d0963fSdilpreet 	ep->payloadprops = NULL;
1764b7d3956bSstephh 	ep->serdprops = NULL;
176500d0963fSdilpreet 	ep->bubbles = NULL;
176600d0963fSdilpreet 	ep->nvp = NULL;
176700d0963fSdilpreet }
176800d0963fSdilpreet 
17697c478bd9Sstevel@tonic-gate static void
itree_free_bubble(struct bubble * freeme)17707c478bd9Sstevel@tonic-gate itree_free_bubble(struct bubble *freeme)
17717c478bd9Sstevel@tonic-gate {
1772b5016cbbSstephh 	alloc_xfree(freeme, sizeof (*freeme));
17737c478bd9Sstevel@tonic-gate }
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate static struct bubble *
itree_add_bubble(struct event * eventp,enum bubbletype btype,int nork,int gen)17767c478bd9Sstevel@tonic-gate itree_add_bubble(struct event *eventp, enum bubbletype btype, int nork, int gen)
17777c478bd9Sstevel@tonic-gate {
17787c478bd9Sstevel@tonic-gate 	struct bubble *prev = NULL;
17797c478bd9Sstevel@tonic-gate 	struct bubble *curr;
17807c478bd9Sstevel@tonic-gate 	struct bubble *newb;
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 	/* Use existing bubbles as appropriate when possible */
17837c478bd9Sstevel@tonic-gate 	for (curr = eventp->bubbles;
17847c478bd9Sstevel@tonic-gate 	    curr != NULL;
17857c478bd9Sstevel@tonic-gate 	    prev = curr, curr = curr->next) {
17867c478bd9Sstevel@tonic-gate 		if (btype == B_TO && curr->t == B_TO) {
17877c478bd9Sstevel@tonic-gate 			/* see if an existing "to" bubble works for us */
17887c478bd9Sstevel@tonic-gate 			if (gen == curr->gen)
17897c478bd9Sstevel@tonic-gate 				return (curr);	/* matched gen number */
17907c478bd9Sstevel@tonic-gate 			else if (nork == 1 && curr->nork == 1) {
17917c478bd9Sstevel@tonic-gate 				curr->gen = gen;
17927c478bd9Sstevel@tonic-gate 				return (curr);	/* coalesce K==1 bubbles */
17937c478bd9Sstevel@tonic-gate 			}
17947c478bd9Sstevel@tonic-gate 		} else if (btype == B_FROM && curr->t == B_FROM) {
17957c478bd9Sstevel@tonic-gate 			/* see if an existing "from" bubble works for us */
17967c478bd9Sstevel@tonic-gate 			if ((nork == N_IS_ALL && curr->nork == N_IS_ALL) ||
17977c478bd9Sstevel@tonic-gate 			    (nork == 0 && curr->nork == 0))
17987c478bd9Sstevel@tonic-gate 				return (curr);
17997c478bd9Sstevel@tonic-gate 		}
18007c478bd9Sstevel@tonic-gate 	}
18017c478bd9Sstevel@tonic-gate 
1802b5016cbbSstephh 	newb = alloc_xmalloc(sizeof (struct bubble));
18037c478bd9Sstevel@tonic-gate 	newb->next = NULL;
18047c478bd9Sstevel@tonic-gate 	newb->t = btype;
18057c478bd9Sstevel@tonic-gate 	newb->myevent = eventp;
18067c478bd9Sstevel@tonic-gate 	newb->nork = nork;
18077c478bd9Sstevel@tonic-gate 	newb->mark = 0;
18087c478bd9Sstevel@tonic-gate 	newb->gen = gen;
18097c478bd9Sstevel@tonic-gate 	newb->arrows = NULL;
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 	if (prev == NULL)
18127c478bd9Sstevel@tonic-gate 		eventp->bubbles = newb;
18137c478bd9Sstevel@tonic-gate 	else
18147c478bd9Sstevel@tonic-gate 		prev->next = newb;
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 	return (newb);
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate struct bubble *
itree_next_bubble(struct event * eventp,struct bubble * last)18207c478bd9Sstevel@tonic-gate itree_next_bubble(struct event *eventp, struct bubble *last)
18217c478bd9Sstevel@tonic-gate {
18227c478bd9Sstevel@tonic-gate 	struct bubble *next;
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 	for (;;) {
18257c478bd9Sstevel@tonic-gate 		if (last != NULL)
18267c478bd9Sstevel@tonic-gate 			next = last->next;
18277c478bd9Sstevel@tonic-gate 		else
18287c478bd9Sstevel@tonic-gate 			next = eventp->bubbles;
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 		if (next == NULL || next->arrows != NULL)
18317c478bd9Sstevel@tonic-gate 			return (next);
18327c478bd9Sstevel@tonic-gate 
18337c478bd9Sstevel@tonic-gate 		/* bubble was empty, skip it */
18347c478bd9Sstevel@tonic-gate 		last = next;
18357c478bd9Sstevel@tonic-gate 	}
18367c478bd9Sstevel@tonic-gate }
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate static void
add_arrow(struct bubble * bp,struct arrow * ap)18397c478bd9Sstevel@tonic-gate add_arrow(struct bubble *bp, struct arrow *ap)
18407c478bd9Sstevel@tonic-gate {
18417c478bd9Sstevel@tonic-gate 	struct arrowlist *prev = NULL;
18427c478bd9Sstevel@tonic-gate 	struct arrowlist *curr;
18437c478bd9Sstevel@tonic-gate 	struct arrowlist *newal;
18447c478bd9Sstevel@tonic-gate 
1845b5016cbbSstephh 	newal = alloc_xmalloc(sizeof (struct arrowlist));
18467c478bd9Sstevel@tonic-gate 	bzero(newal, sizeof (struct arrowlist));
18477c478bd9Sstevel@tonic-gate 	newal->arrowp = ap;
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 	curr = itree_next_arrow(bp, NULL);
18507c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
18517c478bd9Sstevel@tonic-gate 		prev = curr;
18527c478bd9Sstevel@tonic-gate 		curr = itree_next_arrow(bp, curr);
18537c478bd9Sstevel@tonic-gate 	}
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	if (prev == NULL)
18567c478bd9Sstevel@tonic-gate 		bp->arrows = newal;
18577c478bd9Sstevel@tonic-gate 	else
18587c478bd9Sstevel@tonic-gate 		prev->next = newal;
18597c478bd9Sstevel@tonic-gate }
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate static struct arrow *
itree_add_arrow(struct node * apnode,struct node * fromevent,struct node * toevent,struct lut * ex)1862b5016cbbSstephh itree_add_arrow(struct node *apnode, struct node *fromevent,
1863b5016cbbSstephh     struct node *toevent, struct lut *ex)
18647c478bd9Sstevel@tonic-gate {
18657c478bd9Sstevel@tonic-gate 	struct arrow *newa;
18667c478bd9Sstevel@tonic-gate 
1867b5016cbbSstephh 	newa = alloc_xmalloc(sizeof (struct arrow));
18687aec1d6eScindi 	bzero(newa, sizeof (struct arrow));
18697c478bd9Sstevel@tonic-gate 	newa->pnode = apnode;
18707c478bd9Sstevel@tonic-gate 	newa->constraints = NULL;
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	/*
18737c478bd9Sstevel@tonic-gate 	 *  Set default delays, then try to re-set them from
18747c478bd9Sstevel@tonic-gate 	 *  any within() constraints.
18757c478bd9Sstevel@tonic-gate 	 */
18767c478bd9Sstevel@tonic-gate 	newa->mindelay = newa->maxdelay = 0ULL;
18777c478bd9Sstevel@tonic-gate 	if (itree_set_arrow_traits(newa, fromevent, toevent, ex) == 0) {
1878b5016cbbSstephh 		alloc_xfree(newa, sizeof (struct arrow));
18797c478bd9Sstevel@tonic-gate 		return (NULL);
18807c478bd9Sstevel@tonic-gate 	}
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 	return (newa);
18837c478bd9Sstevel@tonic-gate }
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate /* returns false if traits show that arrow should not be added after all */
18867c478bd9Sstevel@tonic-gate static int
itree_set_arrow_traits(struct arrow * ap,struct node * fromev,struct node * toev,struct lut * ex)18877c478bd9Sstevel@tonic-gate itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
18887c478bd9Sstevel@tonic-gate     struct node *toev, struct lut *ex)
18897c478bd9Sstevel@tonic-gate {
1890b5016cbbSstephh 	struct node *events[] = { NULL, NULL, NULL };
18917c478bd9Sstevel@tonic-gate 	struct node *newc = NULL;
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 	ASSERTeq(fromev->t, T_EVENT, ptree_nodetype2str);
18947c478bd9Sstevel@tonic-gate 	ASSERTeq(toev->t, T_EVENT, ptree_nodetype2str);
18957c478bd9Sstevel@tonic-gate 
18967c478bd9Sstevel@tonic-gate 	/*
18977c478bd9Sstevel@tonic-gate 	 * search for the within values first on the declaration of
18987c478bd9Sstevel@tonic-gate 	 * the destination event, and then on the prop.  this allows
18997c478bd9Sstevel@tonic-gate 	 * one to specify a "default" within by putting it on the
19007c478bd9Sstevel@tonic-gate 	 * declaration,  but then allow overriding on the prop statement.
19017c478bd9Sstevel@tonic-gate 	 */
19027c478bd9Sstevel@tonic-gate 	arrow_add_within(ap, toev->u.event.declp->u.stmt.np->u.event.eexprlist);
19037c478bd9Sstevel@tonic-gate 	arrow_add_within(ap, toev->u.event.eexprlist);
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 	/*
19067c478bd9Sstevel@tonic-gate 	 * handle any global constraints inherited from the
19077c478bd9Sstevel@tonic-gate 	 * "fromev" event's declaration
19087c478bd9Sstevel@tonic-gate 	 */
19097c478bd9Sstevel@tonic-gate 	ASSERT(fromev->u.event.declp != NULL);
19107c478bd9Sstevel@tonic-gate 	ASSERT(fromev->u.event.declp->u.stmt.np != NULL);
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate #ifdef	notdef
19137c478bd9Sstevel@tonic-gate 	/* XXX not quite ready to evaluate constraints from decls yet */
19147c478bd9Sstevel@tonic-gate 	if (fromev->u.event.declp->u.stmt.np->u.event.eexprlist)
19157c478bd9Sstevel@tonic-gate 		(void) itree_add_constraint(ap,
19167c478bd9Sstevel@tonic-gate 		    fromev->u.event.declp->u.stmt.np->u.event.eexprlist);
19177c478bd9Sstevel@tonic-gate #endif	/* notdef */
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 	/* handle constraints on the from event in the prop statement */
1920b5016cbbSstephh 	events[0] = fromev;
1921b5016cbbSstephh 	events[1] = toev;
1922b5016cbbSstephh 	if (eval_potential(fromev->u.event.eexprlist, ex, events, &newc,
1923d96ce684Sstephh 	    Ninfo.croot) == 0)
19247c478bd9Sstevel@tonic-gate 		return (0);		/* constraint disallows arrow */
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 	/*
19277c478bd9Sstevel@tonic-gate 	 * handle any global constraints inherited from the
19287c478bd9Sstevel@tonic-gate 	 * "toev" event's declaration
19297c478bd9Sstevel@tonic-gate 	 */
19307c478bd9Sstevel@tonic-gate 	ASSERT(toev->u.event.declp != NULL);
19317c478bd9Sstevel@tonic-gate 	ASSERT(toev->u.event.declp->u.stmt.np != NULL);
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate #ifdef	notdef
19347c478bd9Sstevel@tonic-gate 	/* XXX not quite ready to evaluate constraints from decls yet */
19357c478bd9Sstevel@tonic-gate 	if (toev->u.event.declp->u.stmt.np->u.event.eexprlist)
19367c478bd9Sstevel@tonic-gate 		(void) itree_add_constraint(ap,
19377c478bd9Sstevel@tonic-gate 		    toev->u.event.declp->u.stmt.np->u.event.eexprlist);
19387c478bd9Sstevel@tonic-gate #endif	/* notdef */
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 	/* handle constraints on the to event in the prop statement */
1941b5016cbbSstephh 	events[0] = toev;
1942b5016cbbSstephh 	events[1] = fromev;
1943b5016cbbSstephh 	if (eval_potential(toev->u.event.eexprlist, ex, events, &newc,
1944d96ce684Sstephh 	    Ninfo.croot) == 0) {
194500d0963fSdilpreet 		if (newc != NULL)
194600d0963fSdilpreet 			tree_free(newc);
19477c478bd9Sstevel@tonic-gate 		return (0);		/* constraint disallows arrow */
194800d0963fSdilpreet 	}
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 	/* if we came up with any deferred constraints, add them to arrow */
1951b5016cbbSstephh 	if (newc != NULL) {
1952b5016cbbSstephh 		out(O_ALTFP|O_VERB3, "(deferred constraints)");
19537aec1d6eScindi 		(void) itree_add_constraint(ap, iexpr(newc));
1954b5016cbbSstephh 	}
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 	return (1);	/* constraints allow arrow */
19577c478bd9Sstevel@tonic-gate }
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate /*
19607c478bd9Sstevel@tonic-gate  * Set within() constraint.  If the constraint were set multiple times,
19617c478bd9Sstevel@tonic-gate  * the last one would "win".
19627c478bd9Sstevel@tonic-gate  */
19637c478bd9Sstevel@tonic-gate static void
arrow_add_within(struct arrow * ap,struct node * xpr)19647c478bd9Sstevel@tonic-gate arrow_add_within(struct arrow *ap, struct node *xpr)
19657c478bd9Sstevel@tonic-gate {
19667c478bd9Sstevel@tonic-gate 	struct node *arglist;
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate 	/* end of expressions list */
19697c478bd9Sstevel@tonic-gate 	if (xpr == NULL)
19707c478bd9Sstevel@tonic-gate 		return;
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 	switch (xpr->t) {
19737c478bd9Sstevel@tonic-gate 	case T_LIST:
19747c478bd9Sstevel@tonic-gate 		arrow_add_within(ap, xpr->u.expr.left);
19757c478bd9Sstevel@tonic-gate 		arrow_add_within(ap, xpr->u.expr.right);
19767c478bd9Sstevel@tonic-gate 		return;
19777c478bd9Sstevel@tonic-gate 	case T_FUNC:
19787c478bd9Sstevel@tonic-gate 		if (xpr->u.func.s != L_within)
19797c478bd9Sstevel@tonic-gate 			return;
19807c478bd9Sstevel@tonic-gate 		arglist = xpr->u.func.arglist;
19817c478bd9Sstevel@tonic-gate 		switch (arglist->t) {
19827c478bd9Sstevel@tonic-gate 		case T_TIMEVAL:
19837c478bd9Sstevel@tonic-gate 			ap->mindelay = 0;
19847c478bd9Sstevel@tonic-gate 			ap->maxdelay = arglist->u.ull;
19857c478bd9Sstevel@tonic-gate 			break;
19867c478bd9Sstevel@tonic-gate 		case T_NAME:
19877c478bd9Sstevel@tonic-gate 			ASSERT(arglist->u.name.s == L_infinity);
19887c478bd9Sstevel@tonic-gate 			ap->mindelay = 0;
19897c478bd9Sstevel@tonic-gate 			ap->maxdelay = TIMEVAL_EVENTUALLY;
19907c478bd9Sstevel@tonic-gate 			break;
19917c478bd9Sstevel@tonic-gate 		case T_LIST:
19927c478bd9Sstevel@tonic-gate 			ASSERT(arglist->u.expr.left->t == T_TIMEVAL);
19937c478bd9Sstevel@tonic-gate 			ap->mindelay = arglist->u.expr.left->u.ull;
19947c478bd9Sstevel@tonic-gate 			switch (arglist->u.expr.right->t) {
19957c478bd9Sstevel@tonic-gate 			case T_TIMEVAL:
19967c478bd9Sstevel@tonic-gate 				ap->maxdelay = arglist->u.ull;
19977c478bd9Sstevel@tonic-gate 				break;
19987c478bd9Sstevel@tonic-gate 			case T_NAME:
19997c478bd9Sstevel@tonic-gate 				ASSERT(arglist->u.expr.right->u.name.s ==
20007c478bd9Sstevel@tonic-gate 				    L_infinity);
20017c478bd9Sstevel@tonic-gate 				ap->maxdelay = TIMEVAL_EVENTUALLY;
20027c478bd9Sstevel@tonic-gate 				break;
20037c478bd9Sstevel@tonic-gate 			default:
20047c478bd9Sstevel@tonic-gate 				out(O_DIE, "within: unexpected 2nd arg type");
20057c478bd9Sstevel@tonic-gate 			}
20067c478bd9Sstevel@tonic-gate 			break;
20077c478bd9Sstevel@tonic-gate 		default:
20087c478bd9Sstevel@tonic-gate 			out(O_DIE, "within: unexpected 1st arg type");
20097c478bd9Sstevel@tonic-gate 		}
20107c478bd9Sstevel@tonic-gate 		break;
20117c478bd9Sstevel@tonic-gate 	default:
20127c478bd9Sstevel@tonic-gate 		return;
20137c478bd9Sstevel@tonic-gate 	}
20147c478bd9Sstevel@tonic-gate }
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate static void
itree_free_arrowlists(struct bubble * bubp,int arrows_too)20177c478bd9Sstevel@tonic-gate itree_free_arrowlists(struct bubble *bubp, int arrows_too)
20187c478bd9Sstevel@tonic-gate {
20197c478bd9Sstevel@tonic-gate 	struct arrowlist *al, *nal;
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 	al = bubp->arrows;
20227c478bd9Sstevel@tonic-gate 	while (al != NULL) {
20237c478bd9Sstevel@tonic-gate 		nal = al->next;
20247c478bd9Sstevel@tonic-gate 		if (arrows_too) {
20257c478bd9Sstevel@tonic-gate 			itree_free_constraints(al->arrowp);
2026b5016cbbSstephh 			alloc_xfree(al->arrowp, sizeof (struct arrow));
20277c478bd9Sstevel@tonic-gate 		}
2028b5016cbbSstephh 		alloc_xfree(al, sizeof (*al));
20297c478bd9Sstevel@tonic-gate 		al = nal;
20307c478bd9Sstevel@tonic-gate 	}
20317c478bd9Sstevel@tonic-gate }
20327c478bd9Sstevel@tonic-gate 
203300d0963fSdilpreet static void
itree_delete_arrow(struct bubble * bubp,struct arrow * arrow)203400d0963fSdilpreet itree_delete_arrow(struct bubble *bubp, struct arrow *arrow)
203500d0963fSdilpreet {
203600d0963fSdilpreet 	struct arrowlist *al, *oal;
203700d0963fSdilpreet 
203800d0963fSdilpreet 	al = bubp->arrows;
203900d0963fSdilpreet 	if (al->arrowp == arrow) {
204000d0963fSdilpreet 		bubp->arrows = al->next;
2041b5016cbbSstephh 		alloc_xfree(al, sizeof (*al));
204200d0963fSdilpreet 		return;
204300d0963fSdilpreet 	}
204400d0963fSdilpreet 	while (al != NULL) {
204500d0963fSdilpreet 		oal = al;
204600d0963fSdilpreet 		al = al->next;
204700d0963fSdilpreet 		ASSERT(al != NULL);
204800d0963fSdilpreet 		if (al->arrowp == arrow) {
204900d0963fSdilpreet 			oal->next = al->next;
2050b5016cbbSstephh 			alloc_xfree(al, sizeof (*al));
205100d0963fSdilpreet 			return;
205200d0963fSdilpreet 		}
205300d0963fSdilpreet 	}
205400d0963fSdilpreet }
205500d0963fSdilpreet 
205600d0963fSdilpreet static void
itree_prune_arrowlists(struct bubble * bubp)205700d0963fSdilpreet itree_prune_arrowlists(struct bubble *bubp)
205800d0963fSdilpreet {
205900d0963fSdilpreet 	struct arrowlist *al, *nal;
206000d0963fSdilpreet 
206100d0963fSdilpreet 	al = bubp->arrows;
206200d0963fSdilpreet 	while (al != NULL) {
206300d0963fSdilpreet 		nal = al->next;
206400d0963fSdilpreet 		if (bubp->t == B_FROM)
206500d0963fSdilpreet 			itree_delete_arrow(al->arrowp->head, al->arrowp);
206600d0963fSdilpreet 		else
206700d0963fSdilpreet 			itree_delete_arrow(al->arrowp->tail, al->arrowp);
206800d0963fSdilpreet 		itree_free_constraints(al->arrowp);
2069b5016cbbSstephh 		alloc_xfree(al->arrowp, sizeof (struct arrow));
2070b5016cbbSstephh 		alloc_xfree(al, sizeof (*al));
207100d0963fSdilpreet 		al = nal;
207200d0963fSdilpreet 	}
207300d0963fSdilpreet }
207400d0963fSdilpreet 
20757c478bd9Sstevel@tonic-gate struct arrowlist *
itree_next_arrow(struct bubble * bubble,struct arrowlist * last)20767c478bd9Sstevel@tonic-gate itree_next_arrow(struct bubble *bubble, struct arrowlist *last)
20777c478bd9Sstevel@tonic-gate {
20787c478bd9Sstevel@tonic-gate 	struct arrowlist *next;
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 	if (last != NULL)
20817c478bd9Sstevel@tonic-gate 		next = last->next;
20827c478bd9Sstevel@tonic-gate 	else
20837c478bd9Sstevel@tonic-gate 		next = bubble->arrows;
20847c478bd9Sstevel@tonic-gate 	return (next);
20857c478bd9Sstevel@tonic-gate }
20867c478bd9Sstevel@tonic-gate 
20877c478bd9Sstevel@tonic-gate static struct constraintlist *
itree_add_constraint(struct arrow * arrowp,struct node * c)20887c478bd9Sstevel@tonic-gate itree_add_constraint(struct arrow *arrowp, struct node *c)
20897c478bd9Sstevel@tonic-gate {
20907c478bd9Sstevel@tonic-gate 	struct constraintlist *prev = NULL;
20917c478bd9Sstevel@tonic-gate 	struct constraintlist *curr;
20927c478bd9Sstevel@tonic-gate 	struct constraintlist *newc;
20937c478bd9Sstevel@tonic-gate 
20947c478bd9Sstevel@tonic-gate 	for (curr = arrowp->constraints;
20957c478bd9Sstevel@tonic-gate 	    curr != NULL;
2096b5016cbbSstephh 	    prev = curr, curr = curr->next)
2097b5016cbbSstephh 		;
20987c478bd9Sstevel@tonic-gate 
2099b5016cbbSstephh 	newc = alloc_xmalloc(sizeof (struct constraintlist));
21007c478bd9Sstevel@tonic-gate 	newc->next = NULL;
21017c478bd9Sstevel@tonic-gate 	newc->cnode = c;
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 	if (prev == NULL)
21047c478bd9Sstevel@tonic-gate 		arrowp->constraints = newc;
21057c478bd9Sstevel@tonic-gate 	else
21067c478bd9Sstevel@tonic-gate 		prev->next = newc;
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate 	return (newc);
21097c478bd9Sstevel@tonic-gate }
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate struct constraintlist *
itree_next_constraint(struct arrow * arrowp,struct constraintlist * last)21127c478bd9Sstevel@tonic-gate itree_next_constraint(struct arrow *arrowp, struct constraintlist *last)
21137c478bd9Sstevel@tonic-gate {
21147c478bd9Sstevel@tonic-gate 	struct constraintlist *next;
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 	if (last != NULL)
21177c478bd9Sstevel@tonic-gate 		next = last->next;
21187c478bd9Sstevel@tonic-gate 	else
21197c478bd9Sstevel@tonic-gate 		next = arrowp->constraints;
21207c478bd9Sstevel@tonic-gate 	return (next);
21217c478bd9Sstevel@tonic-gate }
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate static void
itree_free_constraints(struct arrow * ap)21247c478bd9Sstevel@tonic-gate itree_free_constraints(struct arrow *ap)
21257c478bd9Sstevel@tonic-gate {
21267c478bd9Sstevel@tonic-gate 	struct constraintlist *cl, *ncl;
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	cl = ap->constraints;
21297c478bd9Sstevel@tonic-gate 	while (cl != NULL) {
21307c478bd9Sstevel@tonic-gate 		ncl = cl->next;
21317c478bd9Sstevel@tonic-gate 		ASSERT(cl->cnode != NULL);
21327aec1d6eScindi 		if (!iexpr_cached(cl->cnode))
21337c478bd9Sstevel@tonic-gate 			tree_free(cl->cnode);
213400d0963fSdilpreet 		else
213500d0963fSdilpreet 			iexpr_free(cl->cnode);
2136b5016cbbSstephh 		alloc_xfree(cl, sizeof (*cl));
21377c478bd9Sstevel@tonic-gate 		cl = ncl;
21387c478bd9Sstevel@tonic-gate 	}
21397c478bd9Sstevel@tonic-gate }
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate const char *
itree_bubbletype2str(enum bubbletype t)21427c478bd9Sstevel@tonic-gate itree_bubbletype2str(enum bubbletype t)
21437c478bd9Sstevel@tonic-gate {
21447c478bd9Sstevel@tonic-gate 	static char buf[100];
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	switch (t) {
21477c478bd9Sstevel@tonic-gate 	case B_FROM:	return L_from;
21487c478bd9Sstevel@tonic-gate 	case B_TO:	return L_to;
21497c478bd9Sstevel@tonic-gate 	case B_INHIBIT:	return L_inhibit;
21507c478bd9Sstevel@tonic-gate 	default:
21517c478bd9Sstevel@tonic-gate 		(void) sprintf(buf, "[unexpected bubbletype: %d]", t);
21527c478bd9Sstevel@tonic-gate 		return (buf);
21537c478bd9Sstevel@tonic-gate 	}
21547c478bd9Sstevel@tonic-gate }
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate /*
21577c478bd9Sstevel@tonic-gate  * itree_fini -- clean up any half-built itrees
21587c478bd9Sstevel@tonic-gate  */
21597c478bd9Sstevel@tonic-gate void
itree_fini(void)21607c478bd9Sstevel@tonic-gate itree_fini(void)
21617c478bd9Sstevel@tonic-gate {
21627c478bd9Sstevel@tonic-gate 	if (Ninfo.lut != NULL) {
21637c478bd9Sstevel@tonic-gate 		itree_free(Ninfo.lut);
21647c478bd9Sstevel@tonic-gate 		Ninfo.lut = NULL;
21657c478bd9Sstevel@tonic-gate 	}
21667c478bd9Sstevel@tonic-gate 	if (Ninfo.ex) {
21677c478bd9Sstevel@tonic-gate 		lut_free(Ninfo.ex, iterinfo_destructor, NULL);
21687c478bd9Sstevel@tonic-gate 		Ninfo.ex = NULL;
21697c478bd9Sstevel@tonic-gate 	}
21707c478bd9Sstevel@tonic-gate }
2171