Home | History | Annotate | Download | only in eversholt
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  *
     26  * itree.c -- instance tree creation and manipulation
     27  *
     28  * this module provides the instance tree
     29  */
     30 
     31 #include <stdio.h>
     32 #include <ctype.h>
     33 #include <string.h>
     34 #include <strings.h>
     35 #include "alloc.h"
     36 #include "out.h"
     37 #include "stable.h"
     38 #include "literals.h"
     39 #include "lut.h"
     40 #include "tree.h"
     41 #include "ptree.h"
     42 #include "itree.h"
     43 #include "ipath.h"
     44 #include "iexpr.h"
     45 #include "eval.h"
     46 #include "config.h"
     47 
     48 /*
     49  * struct info contains the state we keep when expanding a prop statement
     50  * as part of constructing the instance tree.  state kept in struct info
     51  * is the non-recursive stuff -- the stuff that doesn't need to be on
     52  * the stack.  the rest of the state that is passed between all the
     53  * mutually recursive functions, is required to be on the stack since
     54  * we need to backtrack and recurse as we do the instance tree construction.
     55  */
     56 struct info {
     57 	struct lut *lut;
     58 	struct node *anp;	/* arrow np */
     59 	struct lut *ex;		/* dictionary of explicit iterators */
     60 	struct config *croot;
     61 } Ninfo;
     62 
     63 /*
     64  * struct wildcardinfo is used to track wildcarded portions of paths.
     65  *
     66  * for example, if the epname of an event is "c/d" and the path "a/b/c/d"
     67  * exists, the wildcard path ewname is filled in with the path "a/b".  when
     68  * matching is done, epname is temporarily replaced with the concatenation
     69  * of ewname and epname.
     70  *
     71  * a linked list of these structs is used to track the expansion of each
     72  * event node as it is processed in vmatch() --> vmatch_event() calls.
     73  */
     74 struct wildcardinfo {
     75 	struct node *nptop;		/* event node fed to vmatch */
     76 	struct node *oldepname;		/* epname without the wildcard part */
     77 	struct node *ewname;		/* wildcard path */
     78 	int got_wc_hz;
     79 	struct wildcardinfo *next;
     80 };
     81 
     82 static struct wildcardinfo *wcproot = NULL;
     83 
     84 static void vmatch(struct info *infop, struct node *np, struct node *lnp,
     85     struct node *anp);
     86 static void hmatch(struct info *infop, struct node *np, struct node *nextnp);
     87 static void hmatch_event(struct info *infop, struct node *eventnp,
     88     struct node *epname, struct config *ncp, struct node *nextnp, int rematch);
     89 static void itree_pbubble(int flags, struct bubble *bp);
     90 static void itree_pruner(void *left, void *right, void *arg);
     91 static void itree_destructor(void *left, void *right, void *arg);
     92 static int itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
     93     struct node *toev, struct lut *ex);
     94 static void itree_free_arrowlists(struct bubble *bubp, int arrows_too);
     95 static void itree_prune_arrowlists(struct bubble *bubp);
     96 static void arrow_add_within(struct arrow *ap, struct node *xpr);
     97 static struct arrow *itree_add_arrow(struct node *apnode,
     98     struct node *fromevent, struct node *toevent, struct lut *ex);
     99 static struct event *find_or_add_event(struct info *infop, struct node *np);
    100 static void add_arrow(struct bubble *bp, struct arrow *ap);
    101 static struct constraintlist *itree_add_constraint(struct arrow *arrowp,
    102     struct node *c);
    103 static struct bubble *itree_add_bubble(struct event *eventp,
    104     enum bubbletype btype, int nork, int gen);
    105 static void itree_free_bubble(struct bubble *freeme);
    106 static void itree_free_constraints(struct arrow *ap);
    107 
    108 /*
    109  * the following struct contains the state we build up during
    110  * vertical and horizontal expansion so that generate()
    111  * has everything it needs to construct the appropriate arrows.
    112  * after setting up the state by calling:
    113  *	generate_arrownp()
    114  *	generate_nork()
    115  *	generate_new()
    116  *	generate_from()
    117  *	generate_to()
    118  * the actual arrow generation is done by calling:
    119  *	generate()
    120  */
    121 static struct {
    122 	int generation;		/* generation number of arrow set */
    123 	int matched;		/* number of matches */
    124 	struct node *arrownp;	/* top-level parse tree for arrow */
    125 	int n;			/* n value associated with arrow */
    126 	int k;			/* k value associated with arrow */
    127 	struct node *fromnp;	/* left-hand-side event in parse tree */
    128 	struct node *tonp;	/* right-hand-side event in parse tree */
    129 	struct event *frome;	/* left-hand-side event in instance tree */
    130 	struct event *toe;	/* right-hand-side event in instance tree */
    131 	struct bubble *frombp;	/* bubble arrow comes from */
    132 	struct bubble *tobp;	/* bubble arrow goes to */
    133 } G;
    134 
    135 static void
    136 generate_arrownp(struct node *arrownp)
    137 {
    138 	G.arrownp = arrownp;
    139 }
    140 
    141 static void
    142 generate_nork(int n, int k)
    143 {
    144 	G.n = n;
    145 	G.k = k;
    146 }
    147 
    148 static void
    149 generate_new(void)
    150 {
    151 	G.generation++;
    152 }
    153 
    154 static void
    155 generate_from(struct node *fromeventnp)
    156 {
    157 	G.frombp = NULL;
    158 	G.fromnp = fromeventnp;
    159 }
    160 
    161 static void
    162 generate_to(struct node *toeventnp)
    163 {
    164 	G.tonp = toeventnp;
    165 }
    166 
    167 static void
    168 generate(struct info *infop)
    169 {
    170 	struct arrow *arrowp;
    171 
    172 	ASSERT(G.arrownp != NULL);
    173 	ASSERT(G.fromnp != NULL);
    174 	ASSERT(G.tonp != NULL);
    175 
    176 	out(O_ALTFP|O_VERB3|O_NONL, "        Arrow \"");
    177 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp);
    178 	out(O_ALTFP|O_VERB3|O_NONL, "\" -> \"");
    179 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp);
    180 	out(O_ALTFP|O_VERB3|O_NONL, "\" ");
    181 
    182 	arrowp = itree_add_arrow(G.arrownp, G.fromnp, G.tonp, infop->ex);
    183 	if (arrowp == NULL) {
    184 		out(O_ALTFP|O_VERB3, "(prevented by constraints)");
    185 	} else {
    186 		out(O_ALTFP|O_VERB3, "");
    187 		if (!G.frombp) {
    188 			G.frome = find_or_add_event(infop, G.fromnp);
    189 			G.frombp = itree_add_bubble(G.frome, B_FROM, G.n, 0);
    190 		}
    191 		G.toe = find_or_add_event(infop, G.tonp);
    192 		G.tobp = itree_add_bubble(G.toe, B_TO, G.k, G.generation);
    193 		arrowp->tail = G.frombp;
    194 		arrowp->head = G.tobp;
    195 		add_arrow(G.frombp, arrowp);
    196 		add_arrow(G.tobp, arrowp);
    197 	}
    198 }
    199 
    200 enum childnode_action {
    201 	CN_NONE,
    202 	CN_DUP
    203 };
    204 
    205 static struct node *
    206 tname_dup(struct node *namep, enum childnode_action act)
    207 {
    208 	struct node *retp = NULL;
    209 	const char *file;
    210 	int line;
    211 
    212 	if (namep == NULL)
    213 		return (NULL);
    214 
    215 	file = namep->file;
    216 	line = namep->line;
    217 
    218 	for (; namep != NULL; namep = namep->u.name.next) {
    219 		struct node *newnp = newnode(T_NAME, file, line);
    220 
    221 		newnp->u.name.t = namep->u.name.t;
    222 		newnp->u.name.s = namep->u.name.s;
    223 		newnp->u.name.last = newnp;
    224 		newnp->u.name.it = namep->u.name.it;
    225 		newnp->u.name.cp = namep->u.name.cp;
    226 
    227 		if (act == CN_DUP) {
    228 			struct node *npc;
    229 
    230 			npc = namep->u.name.child;
    231 			if (npc != NULL) {
    232 				switch (npc->t) {
    233 				case T_NUM:
    234 					newnp->u.name.child =
    235 					    newnode(T_NUM, file, line);
    236 					newnp->u.name.child->u.ull =
    237 					    npc->u.ull;
    238 					break;
    239 				case T_NAME:
    240 					newnp->u.name.child =
    241 					    tree_name(npc->u.name.s,
    242 					    npc->u.name.it, file, line);
    243 					break;
    244 				default:
    245 					out(O_DIE, "tname_dup: "
    246 					    "invalid child type %s",
    247 					    ptree_nodetype2str(npc->t));
    248 				}
    249 			}
    250 		}
    251 
    252 		if (retp == NULL) {
    253 			retp = newnp;
    254 		} else {
    255 			retp->u.name.last->u.name.next = newnp;
    256 			retp->u.name.last = newnp;
    257 		}
    258 	}
    259 
    260 	return (retp);
    261 }
    262 
    263 struct prop_wlk_data {
    264 	struct lut *props;
    265 	struct node *epname;
    266 };
    267 
    268 static struct lut *props2instance(struct node *, struct node *);
    269 
    270 /*
    271  * let oldepname be a subset of epname.  return the subsection of epname
    272  * that ends with oldepname.  make each component in the path explicitly
    273  * instanced (i.e., with a T_NUM child).
    274  */
    275 static struct node *
    276 tname_dup_to_epname(struct node *oldepname, struct node *epname)
    277 {
    278 	struct node *npref, *npend, *np1, *np2;
    279 	struct node *ret = NULL;
    280 	int foundmatch = 0;
    281 
    282 	if (epname == NULL)
    283 		return (NULL);
    284 
    285 	/*
    286 	 * search for the longest path in epname which contains
    287 	 * oldnode->u.event.epname.  set npend to point to just past the
    288 	 * end of this path.
    289 	 */
    290 	npend = NULL;
    291 	for (npref = epname; npref; npref = npref->u.name.next) {
    292 		if (npref->u.name.s == oldepname->u.name.s) {
    293 			for (np1 = npref, np2 = oldepname;
    294 			    np1 != NULL && np2 != NULL;
    295 			    np1 = np1->u.name.next, np2 = np2->u.name.next) {
    296 				if (np1->u.name.s != np2->u.name.s)
    297 					break;
    298 			}
    299 			if (np2 == NULL) {
    300 				foundmatch = 1;
    301 				npend = np1;
    302 				if (np1 == NULL) {
    303 					/* oldepname matched npref up to end */
    304 					break;
    305 				}
    306 			}
    307 		}
    308 	}
    309 
    310 	if (foundmatch == 0) {
    311 		/*
    312 		 * if oldepname could not be found in epname, return a
    313 		 * duplicate of the former.  do not try to instantize
    314 		 * oldepname since it might not be a path.
    315 		 */
    316 		return (tname_dup(oldepname, CN_DUP));
    317 	}
    318 
    319 	/*
    320 	 * dup (epname -- npend).  all children should be T_NUMs.
    321 	 */
    322 	for (npref = epname;
    323 	    ! (npref == NULL || npref == npend);
    324 	    npref = npref->u.name.next) {
    325 		struct node *newnp = newnode(T_NAME, oldepname->file,
    326 		    oldepname->line);
    327 
    328 		newnp->u.name.t = npref->u.name.t;
    329 		newnp->u.name.s = npref->u.name.s;
    330 		newnp->u.name.last = newnp;
    331 		newnp->u.name.it = npref->u.name.it;
    332 		newnp->u.name.cp = npref->u.name.cp;
    333 
    334 		newnp->u.name.child = newnode(T_NUM, oldepname->file,
    335 		    oldepname->line);
    336 
    337 		if (npref->u.name.child == NULL ||
    338 		    npref->u.name.child->t != T_NUM) {
    339 			int childnum;
    340 
    341 			ASSERT(npref->u.name.cp != NULL);
    342 			config_getcompname(npref->u.name.cp, NULL, &childnum);
    343 			newnp->u.name.child->u.ull = childnum;
    344 		} else {
    345 			newnp->u.name.child->u.ull =
    346 			    npref->u.name.child->u.ull;
    347 		}
    348 
    349 		if (ret == NULL) {
    350 			ret = newnp;
    351 		} else {
    352 			ret->u.name.last->u.name.next = newnp;
    353 			ret->u.name.last = newnp;
    354 		}
    355 	}
    356 
    357 	return (ret);
    358 }
    359 
    360 /*
    361  * restriction: oldnode->u.event.epname has to be equivalent to or a subset
    362  * of epname
    363  */
    364 static struct node *
    365 tevent_dup_to_epname(struct node *oldnode, struct node *epname)
    366 {
    367 	struct node *ret;
    368 
    369 	ret = newnode(T_EVENT, oldnode->file, oldnode->line);
    370 	ret->u.event.ename = tname_dup(oldnode->u.event.ename, CN_NONE);
    371 	ret->u.event.epname = tname_dup_to_epname(oldnode->u.event.epname,
    372 	    epname);
    373 	return (ret);
    374 }
    375 
    376 static void
    377 nv_instantiate(void *name, void *val, void *arg)
    378 {
    379 	struct prop_wlk_data *pd = (struct prop_wlk_data *)arg;
    380 	struct node *orhs = (struct node *)val;
    381 	struct node *nrhs;
    382 
    383 	/* handle engines by instantizing the entire engine */
    384 	if (name == L_engine) {
    385 		ASSERT(orhs->t == T_EVENT);
    386 		ASSERT(orhs->u.event.ename->u.name.t == N_SERD);
    387 
    388 		/* there are only SERD engines for now */
    389 
    390 		nrhs = newnode(T_SERD, orhs->file, orhs->line);
    391 		nrhs->u.stmt.np = tevent_dup_to_epname(orhs, pd->epname);
    392 		nrhs->u.stmt.lutp = props2instance(orhs, pd->epname);
    393 		pd->props = lut_add(pd->props, name, nrhs, NULL);
    394 		return;
    395 	}
    396 
    397 	switch (orhs->t) {
    398 	case T_NUM:
    399 		nrhs = newnode(T_NUM, orhs->file, orhs->line);
    400 		nrhs->u.ull = orhs->u.ull;
    401 		pd->props = lut_add(pd->props, name, nrhs, NULL);
    402 		break;
    403 	case T_TIMEVAL:
    404 		nrhs = newnode(T_TIMEVAL, orhs->file, orhs->line);
    405 		nrhs->u.ull = orhs->u.ull;
    406 		pd->props = lut_add(pd->props, name, nrhs, NULL);
    407 		break;
    408 	case T_NAME:
    409 		nrhs = tname_dup_to_epname(orhs, pd->epname);
    410 		pd->props = lut_add(pd->props, name, nrhs, NULL);
    411 		break;
    412 	case T_EVENT:
    413 		nrhs = tevent_dup_to_epname(orhs, pd->epname);
    414 		pd->props = lut_add(pd->props, name, nrhs, NULL);
    415 		break;
    416 	case T_GLOBID:
    417 		nrhs = newnode(T_GLOBID, orhs->file, orhs->line);
    418 		nrhs->u.globid.s = orhs->u.globid.s;
    419 		pd->props = lut_add(pd->props, name, nrhs, NULL);
    420 		break;
    421 	case T_FUNC:
    422 		/* for T_FUNC, we don't duplicate it, just point to node */
    423 		pd->props = lut_add(pd->props, name, orhs, NULL);
    424 		break;
    425 	default:
    426 		out(O_DIE, "unexpected nvpair value type %s",
    427 		    ptree_nodetype2str(((struct node *)val)->t));
    428 	}
    429 }
    430 
    431 static struct lut *
    432 props2instance(struct node *eventnp, struct node *epname)
    433 {
    434 	struct prop_wlk_data pd;
    435 
    436 	pd.props = NULL;
    437 	pd.epname = epname;
    438 
    439 	ASSERT(eventnp->u.event.declp != NULL);
    440 	lut_walk(eventnp->u.event.declp->u.stmt.lutp, nv_instantiate, &pd);
    441 	return (pd.props);
    442 }
    443 
    444 /*ARGSUSED*/
    445 static void
    446 instances_destructor(void *left, void *right, void *arg)
    447 {
    448 	struct node *dn = (struct node *)right;
    449 
    450 	if (dn->t == T_SERD) {
    451 		/* we allocated the lut during itree_create(), so free it */
    452 		lut_free(dn->u.stmt.lutp, instances_destructor, NULL);
    453 		dn->u.stmt.lutp = NULL;
    454 	}
    455 	if (dn->t != T_FUNC)	/* T_FUNC pointed to original node */
    456 		tree_free(dn);
    457 }
    458 
    459 /*ARGSUSED*/
    460 static void
    461 payloadprops_destructor(void *left, void *right, void *arg)
    462 {
    463 	FREE(right);
    464 }
    465 
    466 /*ARGSUSED*/
    467 static void
    468 serdprops_destructor(void *left, void *right, void *arg)
    469 {
    470 	FREE(right);
    471 }
    472 
    473 /*
    474  * event_cmp -- used via lut_lookup/lut_add on instance tree lut
    475  */
    476 static int
    477 event_cmp(struct event *ep1, struct event *ep2)
    478 {
    479 	int diff;
    480 
    481 	if ((diff = ep2->enode->u.event.ename->u.name.s -
    482 	    ep1->enode->u.event.ename->u.name.s) != 0)
    483 		return (diff);
    484 	if ((diff = (char *)ep2->ipp - (char *)ep1->ipp) != 0)
    485 		return (diff);
    486 	return (0);
    487 
    488 }
    489 
    490 struct event *
    491 itree_lookup(struct lut *itp, const char *ename, const struct ipath *ipp)
    492 {
    493 	struct event searchevent;	/* just used for searching */
    494 	struct node searcheventnode;
    495 	struct node searchenamenode;
    496 
    497 	searchevent.enode = &searcheventnode;
    498 	searcheventnode.t = T_EVENT;
    499 	searcheventnode.u.event.ename = &searchenamenode;
    500 	searchenamenode.t = T_NAME;
    501 	searchenamenode.u.name.s = ename;
    502 	searchevent.ipp = ipp;
    503 	return (lut_lookup(itp, (void *)&searchevent, (lut_cmp)event_cmp));
    504 }
    505 
    506 static struct event *
    507 find_or_add_event(struct info *infop, struct node *np)
    508 {
    509 	struct event *ret;
    510 	struct event searchevent;	/* just used for searching */
    511 
    512 	ASSERTeq(np->t, T_EVENT, ptree_nodetype2str);
    513 
    514 	searchevent.enode = np;
    515 	searchevent.ipp = ipath(np->u.event.epname);
    516 	if ((ret = lut_lookup(infop->lut, (void *)&searchevent,
    517 	    (lut_cmp)event_cmp)) != NULL)
    518 		return (ret);
    519 
    520 	/* wasn't already in tree, allocate it */
    521 	ret = alloc_xmalloc(sizeof (*ret));
    522 	bzero(ret, sizeof (*ret));
    523 
    524 	ret->t = np->u.event.ename->u.name.t;
    525 	ret->enode = np;
    526 	ret->ipp = searchevent.ipp;
    527 	ret->props = props2instance(np, np->u.event.epname);
    528 
    529 	infop->lut = lut_add(infop->lut, (void *)ret, (void *)ret,
    530 	    (lut_cmp)event_cmp);
    531 
    532 	return (ret);
    533 }
    534 
    535 /*
    536  * Used for handling expansions where first part of oldepname is a horizontal
    537  * expansion. Recurses through entire tree. oldepname argument is always the
    538  * full path as in the rules. Once we find a match we go back to using
    539  * hmatch_event to handle the rest.
    540  */
    541 static void
    542 hmatch_full_config(struct info *infop, struct node *eventnp,
    543     struct node *oldepname, struct config *ncp, struct node *nextnp,
    544     struct iterinfo *iterinfop)
    545 {
    546 	char *cp_s;
    547 	int cp_num;
    548 	struct config *cp;
    549 	struct node *saved_ewname;
    550 	struct node *saved_epname;
    551 	struct config *pcp, *ocp;
    552 	struct node *cpnode;
    553 	struct node *ewlp, *ewfp;
    554 
    555 	for (cp = ncp; cp; cp = config_next(cp)) {
    556 		config_getcompname(cp, &cp_s, &cp_num);
    557 		if (cp_s == oldepname->u.name.s) {
    558 			/*
    559 			 * Found one.
    560 			 */
    561 			iterinfop->num = cp_num;
    562 
    563 			/*
    564 			 * Need to set ewname, epname for correct node as is
    565 			 * needed by constraint path matching. This code is
    566 			 * similar to that in vmatch_event.
    567 			 */
    568 			saved_ewname = eventnp->u.event.ewname;
    569 			saved_epname = eventnp->u.event.epname;
    570 			ocp = oldepname->u.name.cp;
    571 
    572 			/*
    573 			 * Find correct ewname by walking back up the config
    574 			 * tree adding each name portion as we go.
    575 			 */
    576 			pcp = config_parent(cp);
    577 			eventnp->u.event.ewname = NULL;
    578 			for (; pcp != infop->croot; pcp = config_parent(pcp)) {
    579 				config_getcompname(pcp, &cp_s, &cp_num);
    580 				cpnode = tree_name(cp_s, IT_NONE, NULL, 0);
    581 				cpnode->u.name.child = newnode(T_NUM, NULL, 0);
    582 				cpnode->u.name.child->u.ull = cp_num;
    583 				cpnode->u.name.cp = pcp;
    584 				if (eventnp->u.event.ewname != NULL) {
    585 					cpnode->u.name.next =
    586 					    eventnp->u.event.ewname;
    587 					cpnode->u.name.last =
    588 					    eventnp->u.event.ewname->
    589 					    u.name.last;
    590 				}
    591 				eventnp->u.event.ewname = cpnode;
    592 			}
    593 
    594 			/*
    595 			 * Now create correct epname by duping new ewname
    596 			 * and appending oldepname.
    597 			 */
    598 			ewfp = tname_dup(eventnp->u.event.ewname, CN_DUP);
    599 			ewlp = ewfp->u.name.last;
    600 			ewfp->u.name.last = oldepname->u.name.last;
    601 			ewlp->u.name.next = oldepname;
    602 			oldepname->u.name.cp = cp;
    603 			eventnp->u.event.epname = ewfp;
    604 
    605 			outfl(O_ALTFP|O_VERB3|O_NONL, infop->anp->file,
    606 			    infop->anp->line, "hmatch_full_config: ");
    607 			ptree_name_iter(O_ALTFP|O_VERB3|O_NONL,
    608 			    eventnp->u.event.epname);
    609 			out(O_ALTFP|O_VERB3, NULL);
    610 
    611 			/*
    612 			 * Now complete hmatch.
    613 			 */
    614 			hmatch_event(infop, eventnp, oldepname->u.name.next,
    615 			    config_child(cp), nextnp, 1);
    616 
    617 			/*
    618 			 * set everything back again
    619 			 */
    620 			oldepname->u.name.cp = ocp;
    621 			iterinfop->num = -1;
    622 			ewlp->u.name.next = NULL;
    623 			ewfp->u.name.last = ewlp;
    624 			tree_free(ewfp);
    625 			tree_free(eventnp->u.event.ewname);
    626 			eventnp->u.event.ewname = saved_ewname;
    627 			eventnp->u.event.epname = saved_epname;
    628 		}
    629 		/*
    630 		 * Try the next level down.
    631 		 */
    632 		hmatch_full_config(infop, eventnp,
    633 		    oldepname, config_child(cp), nextnp, iterinfop);
    634 	}
    635 }
    636 
    637 /*
    638  * hmatch_event -- perform any appropriate horizontal expansion on an event
    639  *
    640  * this routine is used to perform horizontal expansion on both the
    641  * left-hand-side events in a prop, and the right-hand-side events.
    642  * when called to handle a left-side event, nextnp point to the right
    643  * side of the prop that should be passed to hmatch() for each match
    644  * found by horizontal expansion.   when no horizontal expansion exists,
    645  * we will still "match" one event for every event found in the list on
    646  * the left-hand-side of the prop because vmatch() already found that
    647  * there's at least one match during vertical expansion.
    648  */
    649 static void
    650 hmatch_event(struct info *infop, struct node *eventnp, struct node *epname,
    651     struct config *ncp, struct node *nextnp, int rematch)
    652 {
    653 	if (epname == NULL) {
    654 		/*
    655 		 * end of pathname recursion, either we just located
    656 		 * a left-hand-side event and we're ready to move on
    657 		 * to the expanding the right-hand-side events, or
    658 		 * we're further down the recursion and we just located
    659 		 * a right-hand-side event.  the passed-in parameter
    660 		 * "nextnp" tells us whether we're working on the left
    661 		 * side and need to move on to nextnp, or if nextnp is
    662 		 * NULL, we're working on the right side.
    663 		 */
    664 		if (nextnp) {
    665 			/*
    666 			 * finished a left side expansion, move on to right.
    667 			 * tell generate() what event we just matched so
    668 			 * it can be used at the source of any arrows
    669 			 * we generate as we match events on the right side.
    670 			 */
    671 			generate_from(eventnp);
    672 			hmatch(infop, nextnp, NULL);
    673 		} else {
    674 			/*
    675 			 * finished a right side expansion.  tell generate
    676 			 * the information about the destination and let
    677 			 * it construct the arrows as appropriate.
    678 			 */
    679 			generate_to(eventnp);
    680 			generate(infop);
    681 		}
    682 
    683 		return;
    684 	}
    685 
    686 	ASSERTeq(epname->t, T_NAME, ptree_nodetype2str);
    687 
    688 	if (epname->u.name.cp == NULL)
    689 		return;
    690 
    691 	/*
    692 	 * we only get here when eventnp already has a completely
    693 	 * instanced epname in it already.  so we first recurse
    694 	 * down to the end of the name and as the recursion pops
    695 	 * up, we look for opportunities to advance horizontal
    696 	 * expansions on to the next match.
    697 	 */
    698 	if (epname->u.name.it == IT_HORIZONTAL || rematch) {
    699 		struct config *cp;
    700 		struct config *ocp = epname->u.name.cp;
    701 		char *cp_s;
    702 		int cp_num;
    703 		int ocp_num;
    704 		struct iterinfo *iterinfop = NULL;
    705 		const char *iters;
    706 		int hexpand = 0;
    707 
    708 		if (epname->u.name.it != IT_HORIZONTAL) {
    709 			/*
    710 			 * Ancestor was horizontal though, so must rematch
    711 			 * against the name/num found in vmatch.
    712 			 */
    713 			config_getcompname(ocp, NULL, &ocp_num);
    714 		} else {
    715 			iters = epname->u.name.child->u.name.s;
    716 			if ((iterinfop = lut_lookup(infop->ex,
    717 			    (void *)iters, NULL)) == NULL) {
    718 				/*
    719 				 * do horizontal expansion on this node
    720 				 */
    721 				hexpand = 1;
    722 				iterinfop = alloc_xmalloc(
    723 				    sizeof (struct iterinfo));
    724 				iterinfop->num = -1;
    725 				iterinfop->np = epname;
    726 				infop->ex = lut_add(infop->ex, (void *)iters,
    727 				    iterinfop, NULL);
    728 			} else if (iterinfop->num == -1) {
    729 				hexpand = 1;
    730 			} else {
    731 				/*
    732 				 * This name has already been used in a
    733 				 * horizontal expansion. This time just match it
    734 				 */
    735 				ocp_num = iterinfop->num;
    736 			}
    737 		}
    738 		/*
    739 		 * handle case where this is the first section of oldepname
    740 		 * and it is horizontally expanded. Instead of just looking for
    741 		 * siblings, we want to scan the entire config tree for further
    742 		 * matches.
    743 		 */
    744 		if (epname == eventnp->u.event.oldepname &&
    745 		    epname->u.name.it == IT_HORIZONTAL) {
    746 			/*
    747 			 * Run through config looking for any that match the
    748 			 * name.
    749 			 */
    750 			hmatch_full_config(infop, eventnp, epname,
    751 			    infop->croot, nextnp, iterinfop);
    752 			return;
    753 		}
    754 
    755 		/*
    756 		 * Run through siblings looking for any that match the name.
    757 		 * If hexpand not set then num must also match ocp_num.
    758 		 */
    759 		for (cp = rematch ? ncp : ocp; cp; cp = config_next(cp)) {
    760 			config_getcompname(cp, &cp_s, &cp_num);
    761 			if (cp_s == epname->u.name.s) {
    762 				if (hexpand)
    763 					iterinfop->num = cp_num;
    764 				else if (ocp_num != cp_num)
    765 					continue;
    766 				epname->u.name.cp = cp;
    767 				hmatch_event(infop, eventnp,
    768 				    epname->u.name.next, config_child(cp),
    769 				    nextnp, 1);
    770 			}
    771 		}
    772 		epname->u.name.cp = ocp;
    773 		if (hexpand)
    774 			iterinfop->num = -1;
    775 	} else {
    776 		hmatch_event(infop, eventnp, epname->u.name.next,
    777 		    NULL, nextnp, 0);
    778 	}
    779 }
    780 
    781 /*
    782  * hmatch -- check for horizontal expansion matches
    783  *
    784  * np points to the things we're matching (like a T_LIST or a T_EVENT)
    785  * and if we're working on a left-side of a prop, nextnp points to
    786  * the other side of the prop that we'll tackle next when this recursion
    787  * bottoms out.  when all the events in the entire prop arrow have been
    788  * horizontally expanded, generate() will be called to generate the
    789  * actualy arrow.
    790  */
    791 static void
    792 hmatch(struct info *infop, struct node *np, struct node *nextnp)
    793 {
    794 	if (np == NULL)
    795 		return;		/* all done */
    796 
    797 	/*
    798 	 * for each item in the list of events (which could just
    799 	 * be a single event, or it could get larger in the loop
    800 	 * below due to horizontal expansion), call hmatch on
    801 	 * the right side and create arrows to each element.
    802 	 */
    803 
    804 	switch (np->t) {
    805 	case T_LIST:
    806 		/* loop through the list */
    807 		if (np->u.expr.left)
    808 			hmatch(infop, np->u.expr.left, nextnp);
    809 		if (np->u.expr.right)
    810 			hmatch(infop, np->u.expr.right, nextnp);
    811 		break;
    812 
    813 	case T_EVENT:
    814 		hmatch_event(infop, np, np->u.event.epname,
    815 		    NULL, nextnp, 0);
    816 		break;
    817 
    818 	default:
    819 		outfl(O_DIE, np->file, np->line,
    820 		    "hmatch: unexpected type: %s",
    821 		    ptree_nodetype2str(np->t));
    822 	}
    823 }
    824 
    825 static int
    826 itree_np2nork(struct node *norknp)
    827 {
    828 	if (norknp == NULL)
    829 		return (1);
    830 	else if (norknp->t == T_NAME && norknp->u.name.s == L_A)
    831 		return (-1);	/* our internal version of "all" */
    832 	else if (norknp->t == T_NUM)
    833 		return ((int)norknp->u.ull);
    834 	else
    835 		outfl(O_DIE, norknp->file, norknp->line,
    836 		    "itree_np2nork: internal error type %s",
    837 		    ptree_nodetype2str(norknp->t));
    838 	/*NOTREACHED*/
    839 	return (1);
    840 }
    841 
    842 static struct iterinfo *
    843 newiterinfo(int num, struct node *np)
    844 {
    845 	struct iterinfo *ret = alloc_xmalloc(sizeof (*ret));
    846 
    847 	ret->num = num;
    848 	ret->np = np;
    849 	return (ret);
    850 }
    851 
    852 /*ARGSUSED*/
    853 static void
    854 iterinfo_destructor(void *left, void *right, void *arg)
    855 {
    856 	struct iterinfo *iterinfop = (struct iterinfo *)right;
    857 
    858 	alloc_xfree(iterinfop, sizeof (*iterinfop));
    859 }
    860 
    861 static void
    862 vmatch_event(struct info *infop, struct config *cp, struct node *np,
    863 	    struct node *lnp, struct node *anp, struct wildcardinfo *wcp)
    864 {
    865 	char *cp_s;
    866 	int cp_num;
    867 	struct node *ewlp, *ewfp;
    868 	struct config *pcp;
    869 	struct node *cpnode;
    870 	int newewname = 0;
    871 
    872 	/*
    873 	 * handle case where the first section of the path name is horizontally
    874 	 * expanded. The whole expansion is handled by hmatch on the first
    875 	 * match here - so we just skip any subsequent matches here.
    876 	 */
    877 	if (wcp->got_wc_hz == 1)
    878 		return;
    879 
    880 	if (np == NULL) {
    881 		/*
    882 		 * Reached the end of the name. u.name.cp pointers should be set
    883 		 * up for each part of name. From this we can use config tree
    884 		 * to build up the wildcard part of the name (if any).
    885 		 */
    886 		pcp = config_parent(wcp->nptop->u.event.epname->u.name.cp);
    887 		if (pcp == infop->croot) {
    888 			/*
    889 			 * no wildcarding done - move on to next entry
    890 			 */
    891 			wcp->nptop->u.event.ewname = wcp->ewname;
    892 			wcp->nptop->u.event.oldepname = wcp->oldepname;
    893 			vmatch(infop, np, lnp, anp);
    894 			wcp->got_wc_hz = 0;
    895 			return;
    896 		}
    897 		if (wcp->ewname == NULL) {
    898 			/*
    899 			 * ewname not yet set up - do it now
    900 			 */
    901 			newewname = 1;
    902 			for (; pcp != infop->croot; pcp = config_parent(pcp)) {
    903 				config_getcompname(pcp, &cp_s, &cp_num);
    904 				cpnode = tree_name(cp_s, IT_NONE, NULL, 0);
    905 				cpnode->u.name.child = newnode(T_NUM, NULL, 0);
    906 				cpnode->u.name.child->u.ull = cp_num;
    907 				cpnode->u.name.cp = pcp;
    908 				if (wcp->ewname != NULL) {
    909 					cpnode->u.name.next = wcp->ewname;
    910 					cpnode->u.name.last =
    911 					    wcp->ewname->u.name.last;
    912 				}
    913 				wcp->ewname = cpnode;
    914 			}
    915 		}
    916 
    917 		/*
    918 		 * dup ewname and append oldepname
    919 		 */
    920 		ewfp = tname_dup(wcp->ewname, CN_DUP);
    921 		ewlp = ewfp->u.name.last;
    922 		ewfp->u.name.last = wcp->oldepname->u.name.last;
    923 		ewlp->u.name.next = wcp->oldepname;
    924 
    925 		wcp->nptop->u.event.epname = ewfp;
    926 		wcp->nptop->u.event.ewname = wcp->ewname;
    927 		wcp->nptop->u.event.oldepname = wcp->oldepname;
    928 		vmatch(infop, np, lnp, anp);
    929 		wcp->got_wc_hz = 0;
    930 		wcp->nptop->u.event.epname = wcp->oldepname;
    931 
    932 		/*
    933 		 * reduce duped ewname to original then free
    934 		 */
    935 		ewlp->u.name.next = NULL;
    936 		ewfp->u.name.last = ewlp;
    937 		tree_free(ewfp);
    938 
    939 		if (newewname) {
    940 			/*
    941 			 * free ewname if allocated above
    942 			 */
    943 			tree_free(wcp->ewname);
    944 			wcp->ewname = NULL;
    945 		}
    946 		return;
    947 	}
    948 
    949 	/*
    950 	 * We have an np. See if we can match it in this section of
    951 	 * the config tree.
    952 	 */
    953 	if (cp == NULL)
    954 		return;	/* no more config to match against */
    955 
    956 	for (; cp; cp = config_next(cp)) {
    957 		config_getcompname(cp, &cp_s, &cp_num);
    958 
    959 		if (cp_s == np->u.name.s) {
    960 			/* found a matching component name */
    961 			if (np->u.name.child &&
    962 			    np->u.name.child->t == T_NUM) {
    963 				/*
    964 				 * an explicit instance number was given
    965 				 * in the source.  so only consider this
    966 				 * a configuration match if the number
    967 				 * also matches.
    968 				 */
    969 				if (cp_num != np->u.name.child->u.ull)
    970 					continue;
    971 
    972 			} else if (np->u.name.it != IT_HORIZONTAL) {
    973 				struct iterinfo *iterinfop;
    974 				const char *iters;
    975 
    976 				/*
    977 				 * vertical iterator.  look it up in
    978 				 * the appropriate lut and if we get
    979 				 * back a value it is either one that we
    980 				 * set earlier, in which case we record
    981 				 * the new value for this iteration and
    982 				 * keep matching, or it is one that was
    983 				 * set by an earlier reference to the
    984 				 * iterator, in which case we only consider
    985 				 * this a configuration match if the number
    986 				 * matches cp_num.
    987 				 */
    988 
    989 				ASSERT(np->u.name.child != NULL);
    990 				ASSERT(np->u.name.child->t == T_NAME);
    991 				iters = np->u.name.child->u.name.s;
    992 
    993 				if ((iterinfop = lut_lookup(infop->ex,
    994 				    (void *)iters, NULL)) == NULL) {
    995 					/* we're the first use, record our np */
    996 					infop->ex = lut_add(infop->ex,
    997 					    (void *)iters,
    998 					    newiterinfo(cp_num, np), NULL);
    999 				} else if (np == iterinfop->np) {
   1000 					/*
   1001 					 * we're the first use, back again
   1002 					 * for another iteration.  so update
   1003 					 * the num bound to this iterator in
   1004 					 * the lut.
   1005 					 */
   1006 					iterinfop->num = cp_num;
   1007 				} else if (cp_num != iterinfop->num) {
   1008 					/*
   1009 					 * an earlier reference to this
   1010 					 * iterator bound it to a different
   1011 					 * instance number, so there's no
   1012 					 * match here after all.
   1013 					 *
   1014 					 * however, it's possible that this
   1015 					 * component should really be part of
   1016 					 * the wildcard.  we explore this by
   1017 					 * forcing this component into the
   1018 					 * wildcarded section.
   1019 					 *
   1020 					 * for an more details of what's
   1021 					 * going to happen now, see
   1022 					 * comments block below entitled
   1023 					 * "forcing components into
   1024 					 * wildcard path".
   1025 					 */
   1026 					if (np == wcp->nptop->u.event.epname)
   1027 						vmatch_event(infop,
   1028 						    config_child(cp), np, lnp,
   1029 						    anp, wcp);
   1030 					continue;
   1031 				}
   1032 			}
   1033 
   1034 			/*
   1035 			 * if this was an IT_HORIZONTAL name, hmatch() will
   1036 			 * expand all matches horizontally into a list.
   1037 			 * we know the list will contain at least
   1038 			 * one element (the one we just matched),
   1039 			 * so we just let hmatch_event() do the rest.
   1040 			 *
   1041 			 * recurse on to next component. Note that
   1042 			 * wildcarding is now turned off.
   1043 			 */
   1044 			np->u.name.cp = cp;
   1045 			vmatch_event(infop, config_child(cp), np->u.name.next,
   1046 			    lnp, anp, wcp);
   1047 			np->u.name.cp = NULL;
   1048 
   1049 			/*
   1050 			 * handle case where this is the first section of the
   1051 			 * path name and it is horizontally expanded.
   1052 			 * In this case we want all matching nodes in the config
   1053 			 * to be expanded horizontally - so set got_wc_hz and
   1054 			 * leave all further processing to hmatch.
   1055 			 */
   1056 			if (G.matched && np == wcp->nptop->u.event.epname &&
   1057 			    np->u.name.it == IT_HORIZONTAL)
   1058 				wcp->got_wc_hz = 1;
   1059 
   1060 			/*
   1061 			 * forcing components into wildcard path:
   1062 			 *
   1063 			 * if this component is the first match, force it
   1064 			 * to be part of the wildcarded path and see if we
   1065 			 * can get additional matches.
   1066 			 *
   1067 			 * here's an example.  suppose we have the
   1068 			 * definition
   1069 			 *	event foo@x/y
   1070 			 * and configuration
   1071 			 *	a0/x0/y0/a1/x1/y1
   1072 			 *
   1073 			 * the code up to this point will treat "a0" as the
   1074 			 * wildcarded part of the path and "x0/y0" as the
   1075 			 * nonwildcarded part, resulting in the instanced
   1076 			 * event
   1077 			 *	foo@a0/x0/y0
   1078 			 *
   1079 			 * in order to discover the next match (.../x1/y1)
   1080 			 * in the configuration we have to force "x0" into
   1081 			 * the wildcarded part of the path.
   1082 			 * by doing so, we discover the wildcarded part
   1083 			 * "a0/x0/y0/a1" and the nonwildcarded part "x1/y1"
   1084 			 *
   1085 			 * the following call to vmatch_event() is also
   1086 			 * needed to properly handle the configuration
   1087 			 *	b0/x0/b1/x1/y1
   1088 			 *
   1089 			 * the recursions into vmatch_event() will start
   1090 			 * off uncovering "b0" as the wildcarded part and
   1091 			 * "x0" as the start of the nonwildcarded path.
   1092 			 * however, the next recursion will not result in a
   1093 			 * match since there is no "y" following "x0".  the
   1094 			 * subsequent match of (wildcard = "b0/x0/b1" and
   1095 			 * nonwildcard = "x1/y1") will be discovered only
   1096 			 * if "x0" is forced to be a part of the wildcarded
   1097 			 * path.
   1098 			 */
   1099 			if (np == wcp->nptop->u.event.epname)
   1100 				vmatch_event(infop, config_child(cp), np, lnp,
   1101 				    anp, wcp);
   1102 
   1103 			if (np->u.name.it == IT_HORIZONTAL) {
   1104 				/*
   1105 				 * hmatch() finished iterating through
   1106 				 * the configuration as described above, so
   1107 				 * don't continue iterating here.
   1108 				 */
   1109 				return;
   1110 			}
   1111 		} else if (np == wcp->nptop->u.event.epname) {
   1112 			/*
   1113 			 * no match - carry on down the tree looking for
   1114 			 * wildcarding
   1115 			 */
   1116 			vmatch_event(infop, config_child(cp), np, lnp, anp,
   1117 			    wcp);
   1118 		}
   1119 	}
   1120 }
   1121 
   1122 /*
   1123  * vmatch -- find the next vertical expansion match in the config database
   1124  *
   1125  * this routine is called with three node pointers:
   1126  *	 np -- the parse we're matching
   1127  *	lnp -- the rest of the list we're currently working on
   1128  *	anp -- the rest of the arrow we're currently working on
   1129  *
   1130  * the expansion matching happens via three types of recursion:
   1131  *
   1132  *	- when given an arrow, handle the left-side and then recursively
   1133  *	  handle the right side (which might be another cascaded arrow).
   1134  *
   1135  *	- when handling one side of an arrow, recurse through the T_LIST
   1136  *	  to get to each event (or just move on to the event if there
   1137  *	  is a single event instead of a list)  since the arrow parse
   1138  *	  trees recurse left, we actually start with the right-most
   1139  *	  event list in the prop statement and work our way towards
   1140  *	  the left-most event list.
   1141  *
   1142  *	- when handling an event, recurse down each component of the
   1143  *	  pathname, matching in the config database and recording the
   1144  *	  matches in the explicit iterator dictionary as we go.
   1145  *
   1146  * when the bottom of this matching recursion is met, meaning we have
   1147  * set the "cp" pointers on all the names in the entire statement,
   1148  * we call hmatch() which does it's own recursion to handle horizontal
   1149  * expandsion and then call generate() to generate nodes, bubbles, and
   1150  * arrows in the instance tree.  generate() looks at the cp pointers to
   1151  * see what instance numbers were matched in the configuration database.
   1152  *
   1153  * when horizontal expansion appears, vmatch() finds only the first match
   1154  * and hmatch() then takes the horizontal expansion through all the other
   1155  * matches when generating the arrows in the instance tree.
   1156  *
   1157  * the "infop" passed down through the recursion contains a dictionary
   1158  * of the explicit iterators (all the implicit iterators have been converted
   1159  * to explicit iterators when the parse tree was created by tree.c), which
   1160  * allows things like this to work correctly:
   1161  *
   1162  *	prop error.a@x[n]/y/z -> error.b@x/y[n]/z -> error.c@x/y/z[n];
   1163  *
   1164  * during the top level call, the explicit iterator "n" will match an
   1165  * instance number in the config database, and the result will be recorded
   1166  * in the explicit iterator dictionary and passed down via "infop".  so
   1167  * when the recursive call tries to match y[n] in the config database, it
   1168  * will only match the same instance number as x[n] did since the dictionary
   1169  * is consulted to see if "n" took on a value already.
   1170  *
   1171  * at any point during the recursion, match*() can return to indicate
   1172  * a match was not found in the config database and that the caller should
   1173  * move on to the next potential match, if any.
   1174  *
   1175  * constraints are completely ignored by match(), so the statement:
   1176  *
   1177  *	prop error.a@x[n] -> error.b@x[n] {n != 0};
   1178  *
   1179  * might very well match x[0] if it appears in the config database.  it
   1180  * is the generate() routine that takes that match and then decides what
   1181  * arrow, if any, should be generated in the instance tree.  generate()
   1182  * looks at the explicit iterator dictionary to get values like "n" in
   1183  * the above example so that it can evaluate constraints.
   1184  *
   1185  */
   1186 static void
   1187 vmatch(struct info *infop, struct node *np, struct node *lnp, struct node *anp)
   1188 {
   1189 	struct node *np1, *np2, *oldepname, *oldnptop;
   1190 	int epmatches;
   1191 	struct config *cp;
   1192 	struct wildcardinfo *wcp;
   1193 
   1194 	if (np == NULL) {
   1195 		G.matched = 1;
   1196 		if (lnp)
   1197 			vmatch(infop, lnp, NULL, anp);
   1198 		else if (anp)
   1199 			vmatch(infop, anp, NULL, NULL);
   1200 		else {
   1201 			struct node *src;
   1202 			struct node *dst;
   1203 
   1204 			/* end of vertical match recursion */
   1205 			outfl(O_ALTFP|O_VERB3|O_NONL,
   1206 			    infop->anp->file, infop->anp->line, "vmatch: ");
   1207 			ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, infop->anp);
   1208 			out(O_ALTFP|O_VERB3, NULL);
   1209 
   1210 			generate_nork(
   1211 			    itree_np2nork(infop->anp->u.arrow.nnp),
   1212 			    itree_np2nork(infop->anp->u.arrow.knp));
   1213 			dst = infop->anp->u.arrow.rhs;
   1214 			src = infop->anp->u.arrow.lhs;
   1215 			for (;;) {
   1216 				generate_new();	/* new set of arrows */
   1217 				if (src->t == T_ARROW) {
   1218 					hmatch(infop, src->u.arrow.rhs, dst);
   1219 					generate_nork(
   1220 					    itree_np2nork(src->u.arrow.nnp),
   1221 					    itree_np2nork(src->u.arrow.knp));
   1222 					dst = src->u.arrow.rhs;
   1223 					src = src->u.arrow.lhs;
   1224 				} else {
   1225 					hmatch(infop, src, dst);
   1226 					break;
   1227 				}
   1228 			}
   1229 		}
   1230 		return;
   1231 	}
   1232 
   1233 	switch (np->t) {
   1234 	case T_EVENT: {
   1235 		epmatches = 0;
   1236 		/*
   1237 		 * see if we already have a match in the wcps
   1238 		 */
   1239 		for (wcp = wcproot; wcp; wcp = wcp->next) {
   1240 			oldepname = wcp->oldepname;
   1241 			oldnptop = wcp->nptop;
   1242 			for (np1 = oldepname, np2 = np->u.event.epname;
   1243 			    np1 != NULL && np2 != NULL; np1 = np1->u.name.next,
   1244 			    np2 = np2->u.name.next) {
   1245 				if (strcmp(np1->u.name.s, np2->u.name.s) != 0)
   1246 					break;
   1247 				if (np1->u.name.child->t !=
   1248 				    np2->u.name.child->t)
   1249 					break;
   1250 				if (np1->u.name.child->t == T_NUM &&
   1251 				    np1->u.name.child->u.ull !=
   1252 				    np2->u.name.child->u.ull)
   1253 					break;
   1254 				if (np1->u.name.child->t == T_NAME &&
   1255 				    strcmp(np1->u.name.child->u.name.s,
   1256 				    np2->u.name.child->u.name.s) != 0)
   1257 					break;
   1258 				epmatches++;
   1259 			}
   1260 			if (epmatches)
   1261 				break;
   1262 		}
   1263 		if (epmatches && np1 == NULL && np2 == NULL) {
   1264 			/*
   1265 			 * complete names match, can just borrow the fields
   1266 			 */
   1267 			oldepname = np->u.event.epname;
   1268 			np->u.event.epname = oldnptop->u.event.epname;
   1269 			np->u.event.oldepname = wcp->oldepname;
   1270 			np->u.event.ewname = wcp->ewname;
   1271 			vmatch(infop, NULL, lnp, anp);
   1272 			np->u.event.epname = oldepname;
   1273 			return;
   1274 		}
   1275 		G.matched = 0;
   1276 		if (epmatches) {
   1277 			/*
   1278 			 * just first part of names match - do wildcarding
   1279 			 * by using existing wcp including ewname and also
   1280 			 * copying as much of pwname as is valid, then start
   1281 			 * vmatch_event() at start of non-matching section
   1282 			 */
   1283 			for (np1 = oldepname, np2 = np->u.event.epname;
   1284 			    epmatches != 0; epmatches--) {
   1285 				cp = np1->u.name.cp;
   1286 				np2->u.name.cp = cp;
   1287 				np1 = np1->u.name.next;
   1288 				np2 = np2->u.name.next;
   1289 			}
   1290 			wcp->oldepname = np->u.event.epname;
   1291 			wcp->nptop = np;
   1292 			vmatch_event(infop, config_child(cp), np2, lnp,
   1293 			    anp, wcp);
   1294 			wcp->oldepname = oldepname;
   1295 			wcp->nptop = oldnptop;
   1296 			if (G.matched == 0) {
   1297 				/*
   1298 				 * This list entry is NULL. Move on to next item
   1299 				 * in the list.
   1300 				 */
   1301 				vmatch(infop, NULL, lnp, anp);
   1302 			}
   1303 			return;
   1304 		}
   1305 		/*
   1306 		 * names do not match - allocate a new wcp
   1307 		 */
   1308 		wcp = MALLOC(sizeof (struct wildcardinfo));
   1309 		wcp->next = wcproot;
   1310 		wcproot = wcp;
   1311 		wcp->nptop = np;
   1312 		wcp->oldepname = np->u.event.epname;
   1313 		wcp->ewname = NULL;
   1314 		wcp->got_wc_hz = 0;
   1315 
   1316 		vmatch_event(infop, config_child(infop->croot),
   1317 		    np->u.event.epname, lnp, anp, wcp);
   1318 
   1319 		wcproot = wcp->next;
   1320 		FREE(wcp);
   1321 		if (G.matched == 0) {
   1322 			/*
   1323 			 * This list entry is NULL. Move on to next item in the
   1324 			 * list.
   1325 			 */
   1326 			vmatch(infop, NULL, lnp, anp);
   1327 		}
   1328 		break;
   1329 	}
   1330 	case T_LIST:
   1331 		ASSERT(lnp == NULL);
   1332 		vmatch(infop, np->u.expr.right, np->u.expr.left, anp);
   1333 		break;
   1334 
   1335 	case T_ARROW:
   1336 		ASSERT(lnp == NULL && anp == NULL);
   1337 		vmatch(infop, np->u.arrow.rhs, NULL, np->u.arrow.parent);
   1338 		break;
   1339 
   1340 	default:
   1341 		outfl(O_DIE, np->file, np->line,
   1342 		    "vmatch: unexpected type: %s",
   1343 		    ptree_nodetype2str(np->t));
   1344 	}
   1345 }
   1346 
   1347 static void
   1348 find_first_arrow(struct info *infop, struct node *anp)
   1349 {
   1350 	if (anp->u.arrow.lhs->t == T_ARROW) {
   1351 		anp->u.arrow.lhs->u.arrow.parent = anp;
   1352 		find_first_arrow(infop, anp->u.arrow.lhs);
   1353 	} else
   1354 		vmatch(infop, anp->u.arrow.lhs, NULL, anp);
   1355 }
   1356 
   1357 static void
   1358 cp_reset(struct node *np)
   1359 {
   1360 	if (np == NULL)
   1361 		return;
   1362 	switch (np->t) {
   1363 	case T_NAME:
   1364 		np->u.name.cp = NULL;
   1365 		cp_reset(np->u.name.next);
   1366 		break;
   1367 
   1368 	case T_LIST:
   1369 		cp_reset(np->u.expr.left);
   1370 		cp_reset(np->u.expr.right);
   1371 		break;
   1372 
   1373 	case T_ARROW:
   1374 		cp_reset(np->u.arrow.lhs);
   1375 		cp_reset(np->u.arrow.rhs);
   1376 		break;
   1377 
   1378 	case T_EVENT:
   1379 		cp_reset(np->u.event.epname);
   1380 		break;
   1381 	}
   1382 }
   1383 
   1384 /*
   1385  * itree_create -- apply the current config to the current parse tree
   1386  *
   1387  * returns a lut mapping fully-instance-qualified names to struct events.
   1388  *
   1389  */
   1390 struct lut *
   1391 itree_create(struct config *croot)
   1392 {
   1393 	struct lut *retval;
   1394 	struct node *propnp;
   1395 	extern int alloc_total();
   1396 	int init_size;
   1397 
   1398 	Ninfo.lut = NULL;
   1399 	Ninfo.croot = croot;
   1400 	init_size = alloc_total();
   1401 	out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size);
   1402 	for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
   1403 		struct node *anp = propnp->u.stmt.np;
   1404 
   1405 		ASSERTeq(anp->t, T_ARROW, ptree_nodetype2str);
   1406 
   1407 		if (!anp->u.arrow.needed)
   1408 			continue;
   1409 		Ninfo.anp = anp;
   1410 		Ninfo.ex = NULL;
   1411 
   1412 		generate_arrownp(anp);
   1413 		anp->u.arrow.parent = NULL;
   1414 		find_first_arrow(&Ninfo, anp);
   1415 
   1416 		if (Ninfo.ex) {
   1417 			lut_free(Ninfo.ex, iterinfo_destructor, NULL);
   1418 			Ninfo.ex = NULL;
   1419 		}
   1420 		cp_reset(anp);
   1421 	}
   1422 
   1423 	out(O_ALTFP|O_STAMP, "itree_create added %d bytes",
   1424 	    alloc_total() - init_size);
   1425 	retval = Ninfo.lut;
   1426 	Ninfo.lut = NULL;
   1427 	return (retval);
   1428 }
   1429 
   1430 /*
   1431  * initial first pass of the rules.
   1432  * We don't use the config at all. Just check the last part of the pathname
   1433  * in the rules. If this matches the last part of the pathname in the first
   1434  * ereport, then set pathname to the pathname in the ereport. If not then
   1435  * set pathname to just the last part of pathname with instance number 0.
   1436  * Constraints are ignored and all nork values are set to 0. If after all that
   1437  * any rules can still not be associated with the ereport, then they are set
   1438  * to not needed in prune_propagations() and ignored in the real itree_create()
   1439  * which follows.
   1440  */
   1441 
   1442 static struct event *
   1443 add_event_dummy(struct node *np, const struct ipath *ipp)
   1444 {
   1445 	struct event *ret;
   1446 	struct event searchevent;	/* just used for searching */
   1447 	extern struct ipath *ipath_dummy(struct node *, struct ipath *);
   1448 	struct ipath *ipp_un;
   1449 	extern struct ipath *ipath_for_usednames(struct node *);
   1450 
   1451 	searchevent.enode = np;
   1452 	searchevent.ipp = ipath_dummy(np->u.event.epname, (struct ipath *)ipp);
   1453 	ipp_un = ipath_for_usednames(np->u.event.epname);
   1454 	if ((ret = lut_lookup(Ninfo.lut, (void *)&searchevent,
   1455 	    (lut_cmp)event_cmp)) != NULL)
   1456 		return (ret);
   1457 
   1458 	ret = alloc_xmalloc(sizeof (*ret));
   1459 	bzero(ret, sizeof (*ret));
   1460 	ret->t = np->u.event.ename->u.name.t;
   1461 	ret->enode = np;
   1462 	ret->ipp = searchevent.ipp;
   1463 	ret->ipp_un = ipp_un;
   1464 	Ninfo.lut = lut_add(Ninfo.lut, (void *)ret, (void *)ret,
   1465 	    (lut_cmp)event_cmp);
   1466 	return (ret);
   1467 }
   1468 
   1469 /*ARGSUSED*/
   1470 struct lut *
   1471 itree_create_dummy(const char *e0class, const struct ipath *e0ipp)
   1472 {
   1473 	struct node *propnp;
   1474 	struct event *frome, *toe;
   1475 	struct bubble *frombp, *tobp;
   1476 	struct arrow *arrowp;
   1477 	struct node *src, *dst, *slst, *dlst, *arrownp, *oldarrownp;
   1478 	int gen = 0;
   1479 	extern int alloc_total();
   1480 	int init_size;
   1481 
   1482 	Ninfo.lut = NULL;
   1483 	init_size = alloc_total();
   1484 	out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size);
   1485 	for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
   1486 		arrownp = propnp->u.stmt.np;
   1487 		while (arrownp) {
   1488 			gen++;
   1489 			dlst = arrownp->u.arrow.rhs;
   1490 			slst = arrownp->u.arrow.lhs;
   1491 			oldarrownp = arrownp;
   1492 			if (slst->t == T_ARROW) {
   1493 				arrownp = slst;
   1494 				slst = slst->u.arrow.rhs;
   1495 			} else {
   1496 				arrownp = NULL;
   1497 			}
   1498 			while (slst) {
   1499 				if (slst->t == T_LIST) {
   1500 					src = slst->u.expr.right;
   1501 					slst = slst->u.expr.left;
   1502 				} else {
   1503 					src = slst;
   1504 					slst = NULL;
   1505 				}
   1506 				frome = add_event_dummy(src, e0ipp);
   1507 				frombp = itree_add_bubble(frome, B_FROM, 0, 0);
   1508 				while (dlst) {
   1509 					if (dlst->t == T_LIST) {
   1510 						dst = dlst->u.expr.right;
   1511 						dlst = dlst->u.expr.left;
   1512 					} else {
   1513 						dst = dlst;
   1514 						dlst = NULL;
   1515 					}
   1516 					arrowp = alloc_xmalloc(
   1517 					    sizeof (struct arrow));
   1518 					bzero(arrowp, sizeof (struct arrow));
   1519 					arrowp->pnode = oldarrownp;
   1520 					toe = add_event_dummy(dst, e0ipp);
   1521 					tobp = itree_add_bubble(toe, B_TO, 0,
   1522 					    gen);
   1523 					arrowp->tail = frombp;
   1524 					arrowp->head = tobp;
   1525 					add_arrow(frombp, arrowp);
   1526 					add_arrow(tobp, arrowp);
   1527 					arrow_add_within(arrowp,
   1528 					    dst->u.event.declp->u.stmt.np->
   1529 					    u.event.eexprlist);
   1530 					arrow_add_within(arrowp,
   1531 					    dst->u.event.eexprlist);
   1532 				}
   1533 			}
   1534 		}
   1535 	}
   1536 	out(O_ALTFP|O_STAMP, "itree_create added %d bytes",
   1537 	    alloc_total() - init_size);
   1538 	return (Ninfo.lut);
   1539 }
   1540 
   1541 void
   1542 itree_free(struct lut *lutp)
   1543 {
   1544 	int init_size;
   1545 
   1546 	init_size = alloc_total();
   1547 	out(O_ALTFP|O_STAMP, "start itree_free");
   1548 	lut_free(lutp, itree_destructor, NULL);
   1549 	out(O_ALTFP|O_STAMP, "itree_free freed %d bytes",
   1550 	    init_size - alloc_total());
   1551 }
   1552 
   1553 void
   1554 itree_prune(struct lut *lutp)
   1555 {
   1556 	int init_size;
   1557 
   1558 	init_size = alloc_total();
   1559 	out(O_ALTFP|O_STAMP, "start itree_prune");
   1560 	lut_walk(lutp, itree_pruner, NULL);
   1561 	out(O_ALTFP|O_STAMP, "itree_prune freed %d bytes",
   1562 	    init_size - alloc_total());
   1563 }
   1564 
   1565 void
   1566 itree_pevent_brief(int flags, struct event *ep)
   1567 {
   1568 	ASSERT(ep != NULL);
   1569 	ASSERT(ep->enode != NULL);
   1570 	ASSERT(ep->ipp != NULL);
   1571 
   1572 	ipath_print(flags, ep->enode->u.event.ename->u.name.s, ep->ipp);
   1573 }
   1574 
   1575 /*ARGSUSED*/
   1576 static void
   1577 itree_pevent(struct event *lhs, struct event *ep, void *arg)
   1578 {
   1579 	struct plut_wlk_data propd;
   1580 	struct bubble *bp;
   1581 	int flags = (int)(intptr_t)arg;
   1582 
   1583 	itree_pevent_brief(flags, ep);
   1584 	if (ep->t == N_EREPORT)
   1585 		out(flags, " (count %d)", ep->count);
   1586 	else
   1587 		out(flags, NULL);
   1588 
   1589 	if (ep->props) {
   1590 		propd.flags = flags;
   1591 		propd.first = 1;
   1592 		out(flags, "Properties:");
   1593 		lut_walk(ep->props, ptree_plut, (void *)&propd);
   1594 	}
   1595 
   1596 	for (bp = itree_next_bubble(ep, NULL); bp;
   1597 	    bp = itree_next_bubble(ep, bp)) {
   1598 		/* Print only TO bubbles in this loop */
   1599 		if (bp->t != B_TO)
   1600 			continue;
   1601 		itree_pbubble(flags, bp);
   1602 	}
   1603 
   1604 	for (bp = itree_next_bubble(ep, NULL); bp;
   1605 	    bp = itree_next_bubble(ep, bp)) {
   1606 		/* Print only INHIBIT bubbles in this loop */
   1607 		if (bp->t != B_INHIBIT)
   1608 			continue;
   1609 		itree_pbubble(flags, bp);
   1610 	}
   1611 
   1612 	for (bp = itree_next_bubble(ep, NULL); bp;
   1613 	    bp = itree_next_bubble(ep, bp)) {
   1614 		/* Print only FROM bubbles in this loop */
   1615 		if (bp->t != B_FROM)
   1616 			continue;
   1617 		itree_pbubble(flags, bp);
   1618 	}
   1619 }
   1620 
   1621 static void
   1622 itree_pbubble(int flags, struct bubble *bp)
   1623 {
   1624 	struct constraintlist *cp;
   1625 	struct arrowlist *ap;
   1626 
   1627 	ASSERT(bp != NULL);
   1628 
   1629 	out(flags|O_NONL, "   ");
   1630 	if (bp->mark)
   1631 		out(flags|O_NONL, "*");
   1632 	else
   1633 		out(flags|O_NONL, " ");
   1634 	if (bp->t == B_FROM)
   1635 		out(flags|O_NONL, "N=%d to:", bp->nork);
   1636 	else if (bp->t == B_TO)
   1637 		out(flags|O_NONL, "K=%d from:", bp->nork);
   1638 	else
   1639 		out(flags|O_NONL, "K=%d masked from:", bp->nork);
   1640 
   1641 	if (bp->t == B_TO || bp->t == B_INHIBIT) {
   1642 		for (ap = itree_next_arrow(bp, NULL); ap;
   1643 		    ap = itree_next_arrow(bp, ap)) {
   1644 			ASSERT(ap->arrowp->head == bp);
   1645 			ASSERT(ap->arrowp->tail != NULL);
   1646 			ASSERT(ap->arrowp->tail->myevent != NULL);
   1647 			out(flags|O_NONL, " ");
   1648 			itree_pevent_brief(flags, ap->arrowp->tail->myevent);
   1649 		}
   1650 		out(flags, NULL);
   1651 		return;
   1652 	}
   1653 
   1654 	for (ap = itree_next_arrow(bp, NULL); ap;
   1655 	    ap = itree_next_arrow(bp, ap)) {
   1656 		ASSERT(ap->arrowp->tail == bp);
   1657 		ASSERT(ap->arrowp->head != NULL);
   1658 		ASSERT(ap->arrowp->head->myevent != NULL);
   1659 
   1660 		out(flags|O_NONL, " ");
   1661 		itree_pevent_brief(flags, ap->arrowp->head->myevent);
   1662 
   1663 		out(flags|O_NONL, " ");
   1664 		ptree_timeval(flags, &ap->arrowp->mindelay);
   1665 		out(flags|O_NONL, ",");
   1666 		ptree_timeval(flags, &ap->arrowp->maxdelay);
   1667 
   1668 		/* Display anything from the propogation node? */
   1669 		out(O_VERB3|O_NONL, " <%s:%d>",
   1670 		    ap->arrowp->pnode->file, ap->arrowp->pnode->line);
   1671 
   1672 		if (itree_next_constraint(ap->arrowp, NULL))
   1673 			out(flags|O_NONL, " {");
   1674 
   1675 		for (cp = itree_next_constraint(ap->arrowp, NULL); cp;
   1676 		    cp = itree_next_constraint(ap->arrowp, cp)) {
   1677 			ptree(flags, cp->cnode, 1, 0);
   1678 			if (itree_next_constraint(ap->arrowp, cp))
   1679 				out(flags|O_NONL, ", ");
   1680 		}
   1681 
   1682 		if (itree_next_constraint(ap->arrowp, NULL))
   1683 			out(flags|O_NONL, "}");
   1684 	}
   1685 	out(flags, NULL);
   1686 }
   1687 
   1688 void
   1689 itree_ptree(int flags, struct lut *itp)
   1690 {
   1691 	lut_walk(itp, (lut_cb)itree_pevent, (void *)(intptr_t)flags);
   1692 }
   1693 
   1694 /*ARGSUSED*/
   1695 static void
   1696 itree_destructor(void *left, void *right, void *arg)
   1697 {
   1698 	struct event *ep = (struct event *)right;
   1699 	struct bubble *nextbub, *bub;
   1700 
   1701 	/* Free the properties */
   1702 	if (ep->props)
   1703 		lut_free(ep->props, instances_destructor, NULL);
   1704 
   1705 	/* Free the payload properties */
   1706 	if (ep->payloadprops)
   1707 		lut_free(ep->payloadprops, payloadprops_destructor, NULL);
   1708 
   1709 	/* Free the serd properties */
   1710 	if (ep->serdprops)
   1711 		lut_free(ep->serdprops, serdprops_destructor, NULL);
   1712 
   1713 	/* Free my bubbles */
   1714 	for (bub = ep->bubbles; bub != NULL; ) {
   1715 		nextbub = bub->next;
   1716 		/*
   1717 		 * Free arrows if they are FROM me.  Free arrowlists on
   1718 		 * other types of bubbles (but not the attached arrows,
   1719 		 * which will be freed when we free the originating
   1720 		 * bubble.
   1721 		 */
   1722 		if (bub->t == B_FROM)
   1723 			itree_free_arrowlists(bub, 1);
   1724 		else
   1725 			itree_free_arrowlists(bub, 0);
   1726 		itree_free_bubble(bub);
   1727 		bub = nextbub;
   1728 	}
   1729 
   1730 	if (ep->nvp != NULL)
   1731 		nvlist_free(ep->nvp);
   1732 	alloc_xfree(ep, sizeof (*ep));
   1733 }
   1734 
   1735 /*ARGSUSED*/
   1736 static void
   1737 itree_pruner(void *left, void *right, void *arg)
   1738 {
   1739 	struct event *ep = (struct event *)right;
   1740 	struct bubble *nextbub, *bub;
   1741 
   1742 	if (ep->keep_in_tree)
   1743 		return;
   1744 
   1745 	/* Free the properties */
   1746 	lut_free(ep->props, instances_destructor, NULL);
   1747 
   1748 	/* Free the payload properties */
   1749 	lut_free(ep->payloadprops, payloadprops_destructor, NULL);
   1750 
   1751 	/* Free the serd properties */
   1752 	lut_free(ep->serdprops, serdprops_destructor, NULL);
   1753 
   1754 	/* Free my bubbles */
   1755 	for (bub = ep->bubbles; bub != NULL; ) {
   1756 		nextbub = bub->next;
   1757 		itree_prune_arrowlists(bub);
   1758 		itree_free_bubble(bub);
   1759 		bub = nextbub;
   1760 	}
   1761 
   1762 	if (ep->nvp != NULL)
   1763 		nvlist_free(ep->nvp);
   1764 	ep->props = NULL;
   1765 	ep->payloadprops = NULL;
   1766 	ep->serdprops = NULL;
   1767 	ep->bubbles = NULL;
   1768 	ep->nvp = NULL;
   1769 }
   1770 
   1771 static void
   1772 itree_free_bubble(struct bubble *freeme)
   1773 {
   1774 	alloc_xfree(freeme, sizeof (*freeme));
   1775 }
   1776 
   1777 static struct bubble *
   1778 itree_add_bubble(struct event *eventp, enum bubbletype btype, int nork, int gen)
   1779 {
   1780 	struct bubble *prev = NULL;
   1781 	struct bubble *curr;
   1782 	struct bubble *newb;
   1783 
   1784 	/* Use existing bubbles as appropriate when possible */
   1785 	for (curr = eventp->bubbles;
   1786 	    curr != NULL;
   1787 	    prev = curr, curr = curr->next) {
   1788 		if (btype == B_TO && curr->t == B_TO) {
   1789 			/* see if an existing "to" bubble works for us */
   1790 			if (gen == curr->gen)
   1791 				return (curr);	/* matched gen number */
   1792 			else if (nork == 1 && curr->nork == 1) {
   1793 				curr->gen = gen;
   1794 				return (curr);	/* coalesce K==1 bubbles */
   1795 			}
   1796 		} else if (btype == B_FROM && curr->t == B_FROM) {
   1797 			/* see if an existing "from" bubble works for us */
   1798 			if ((nork == N_IS_ALL && curr->nork == N_IS_ALL) ||
   1799 			    (nork == 0 && curr->nork == 0))
   1800 				return (curr);
   1801 		}
   1802 	}
   1803 
   1804 	newb = alloc_xmalloc(sizeof (struct bubble));
   1805 	newb->next = NULL;
   1806 	newb->t = btype;
   1807 	newb->myevent = eventp;
   1808 	newb->nork = nork;
   1809 	newb->mark = 0;
   1810 	newb->gen = gen;
   1811 	newb->arrows = NULL;
   1812 
   1813 	if (prev == NULL)
   1814 		eventp->bubbles = newb;
   1815 	else
   1816 		prev->next = newb;
   1817 
   1818 	return (newb);
   1819 }
   1820 
   1821 struct bubble *
   1822 itree_next_bubble(struct event *eventp, struct bubble *last)
   1823 {
   1824 	struct bubble *next;
   1825 
   1826 	for (;;) {
   1827 		if (last != NULL)
   1828 			next = last->next;
   1829 		else
   1830 			next = eventp->bubbles;
   1831 
   1832 		if (next == NULL || next->arrows != NULL)
   1833 			return (next);
   1834 
   1835 		/* bubble was empty, skip it */
   1836 		last = next;
   1837 	}
   1838 }
   1839 
   1840 static void
   1841 add_arrow(struct bubble *bp, struct arrow *ap)
   1842 {
   1843 	struct arrowlist *prev = NULL;
   1844 	struct arrowlist *curr;
   1845 	struct arrowlist *newal;
   1846 
   1847 	newal = alloc_xmalloc(sizeof (struct arrowlist));
   1848 	bzero(newal, sizeof (struct arrowlist));
   1849 	newal->arrowp = ap;
   1850 
   1851 	curr = itree_next_arrow(bp, NULL);
   1852 	while (curr != NULL) {
   1853 		prev = curr;
   1854 		curr = itree_next_arrow(bp, curr);
   1855 	}
   1856 
   1857 	if (prev == NULL)
   1858 		bp->arrows = newal;
   1859 	else
   1860 		prev->next = newal;
   1861 }
   1862 
   1863 static struct arrow *
   1864 itree_add_arrow(struct node *apnode, struct node *fromevent,
   1865     struct node *toevent, struct lut *ex)
   1866 {
   1867 	struct arrow *newa;
   1868 
   1869 	newa = alloc_xmalloc(sizeof (struct arrow));
   1870 	bzero(newa, sizeof (struct arrow));
   1871 	newa->pnode = apnode;
   1872 	newa->constraints = NULL;
   1873 
   1874 	/*
   1875 	 *  Set default delays, then try to re-set them from
   1876 	 *  any within() constraints.
   1877 	 */
   1878 	newa->mindelay = newa->maxdelay = 0ULL;
   1879 	if (itree_set_arrow_traits(newa, fromevent, toevent, ex) == 0) {
   1880 		alloc_xfree(newa, sizeof (struct arrow));
   1881 		return (NULL);
   1882 	}
   1883 
   1884 	return (newa);
   1885 }
   1886 
   1887 /* returns false if traits show that arrow should not be added after all */
   1888 static int
   1889 itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
   1890     struct node *toev, struct lut *ex)
   1891 {
   1892 	struct node *events[] = { NULL, NULL, NULL };
   1893 	struct node *newc = NULL;
   1894 
   1895 	ASSERTeq(fromev->t, T_EVENT, ptree_nodetype2str);
   1896 	ASSERTeq(toev->t, T_EVENT, ptree_nodetype2str);
   1897 
   1898 	/*
   1899 	 * search for the within values first on the declaration of
   1900 	 * the destination event, and then on the prop.  this allows
   1901 	 * one to specify a "default" within by putting it on the
   1902 	 * declaration,  but then allow overriding on the prop statement.
   1903 	 */
   1904 	arrow_add_within(ap, toev->u.event.declp->u.stmt.np->u.event.eexprlist);
   1905 	arrow_add_within(ap, toev->u.event.eexprlist);
   1906 
   1907 	/*
   1908 	 * handle any global constraints inherited from the
   1909 	 * "fromev" event's declaration
   1910 	 */
   1911 	ASSERT(fromev->u.event.declp != NULL);
   1912 	ASSERT(fromev->u.event.declp->u.stmt.np != NULL);
   1913 
   1914 #ifdef	notdef
   1915 	/* XXX not quite ready to evaluate constraints from decls yet */
   1916 	if (fromev->u.event.declp->u.stmt.np->u.event.eexprlist)
   1917 		(void) itree_add_constraint(ap,
   1918 		    fromev->u.event.declp->u.stmt.np->u.event.eexprlist);
   1919 #endif	/* notdef */
   1920 
   1921 	/* handle constraints on the from event in the prop statement */
   1922 	events[0] = fromev;
   1923 	events[1] = toev;
   1924 	if (eval_potential(fromev->u.event.eexprlist, ex, events, &newc,
   1925 	    Ninfo.croot) == 0)
   1926 		return (0);		/* constraint disallows arrow */
   1927 
   1928 	/*
   1929 	 * handle any global constraints inherited from the
   1930 	 * "toev" event's declaration
   1931 	 */
   1932 	ASSERT(toev->u.event.declp != NULL);
   1933 	ASSERT(toev->u.event.declp->u.stmt.np != NULL);
   1934 
   1935 #ifdef	notdef
   1936 	/* XXX not quite ready to evaluate constraints from decls yet */
   1937 	if (toev->u.event.declp->u.stmt.np->u.event.eexprlist)
   1938 		(void) itree_add_constraint(ap,
   1939 		    toev->u.event.declp->u.stmt.np->u.event.eexprlist);
   1940 #endif	/* notdef */
   1941 
   1942 	/* handle constraints on the to event in the prop statement */
   1943 	events[0] = toev;
   1944 	events[1] = fromev;
   1945 	if (eval_potential(toev->u.event.eexprlist, ex, events, &newc,
   1946 	    Ninfo.croot) == 0) {
   1947 		if (newc != NULL)
   1948 			tree_free(newc);
   1949 		return (0);		/* constraint disallows arrow */
   1950 	}
   1951 
   1952 	/* if we came up with any deferred constraints, add them to arrow */
   1953 	if (newc != NULL) {
   1954 		out(O_ALTFP|O_VERB3, "(deferred constraints)");
   1955 		(void) itree_add_constraint(ap, iexpr(newc));
   1956 	}
   1957 
   1958 	return (1);	/* constraints allow arrow */
   1959 }
   1960 
   1961 /*
   1962  * Set within() constraint.  If the constraint were set multiple times,
   1963  * the last one would "win".
   1964  */
   1965 static void
   1966 arrow_add_within(struct arrow *ap, struct node *xpr)
   1967 {
   1968 	struct node *arglist;
   1969 
   1970 	/* end of expressions list */
   1971 	if (xpr == NULL)
   1972 		return;
   1973 
   1974 	switch (xpr->t) {
   1975 	case T_LIST:
   1976 		arrow_add_within(ap, xpr->u.expr.left);
   1977 		arrow_add_within(ap, xpr->u.expr.right);
   1978 		return;
   1979 	case T_FUNC:
   1980 		if (xpr->u.func.s != L_within)
   1981 			return;
   1982 		arglist = xpr->u.func.arglist;
   1983 		switch (arglist->t) {
   1984 		case T_TIMEVAL:
   1985 			ap->mindelay = 0;
   1986 			ap->maxdelay = arglist->u.ull;
   1987 			break;
   1988 		case T_NAME:
   1989 			ASSERT(arglist->u.name.s == L_infinity);
   1990 			ap->mindelay = 0;
   1991 			ap->maxdelay = TIMEVAL_EVENTUALLY;
   1992 			break;
   1993 		case T_LIST:
   1994 			ASSERT(arglist->u.expr.left->t == T_TIMEVAL);
   1995 			ap->mindelay = arglist->u.expr.left->u.ull;
   1996 			switch (arglist->u.expr.right->t) {
   1997 			case T_TIMEVAL:
   1998 				ap->maxdelay = arglist->u.ull;
   1999 				break;
   2000 			case T_NAME:
   2001 				ASSERT(arglist->u.expr.right->u.name.s ==
   2002 				    L_infinity);
   2003 				ap->maxdelay = TIMEVAL_EVENTUALLY;
   2004 				break;
   2005 			default:
   2006 				out(O_DIE, "within: unexpected 2nd arg type");
   2007 			}
   2008 			break;
   2009 		default:
   2010 			out(O_DIE, "within: unexpected 1st arg type");
   2011 		}
   2012 		break;
   2013 	default:
   2014 		return;
   2015 	}
   2016 }
   2017 
   2018 static void
   2019 itree_free_arrowlists(struct bubble *bubp, int arrows_too)
   2020 {
   2021 	struct arrowlist *al, *nal;
   2022 
   2023 	al = bubp->arrows;
   2024 	while (al != NULL) {
   2025 		nal = al->next;
   2026 		if (arrows_too) {
   2027 			itree_free_constraints(al->arrowp);
   2028 			alloc_xfree(al->arrowp, sizeof (struct arrow));
   2029 		}
   2030 		alloc_xfree(al, sizeof (*al));
   2031 		al = nal;
   2032 	}
   2033 }
   2034 
   2035 static void
   2036 itree_delete_arrow(struct bubble *bubp, struct arrow *arrow)
   2037 {
   2038 	struct arrowlist *al, *oal;
   2039 
   2040 	al = bubp->arrows;
   2041 	if (al->arrowp == arrow) {
   2042 		bubp->arrows = al->next;
   2043 		alloc_xfree(al, sizeof (*al));
   2044 		return;
   2045 	}
   2046 	while (al != NULL) {
   2047 		oal = al;
   2048 		al = al->next;
   2049 		ASSERT(al != NULL);
   2050 		if (al->arrowp == arrow) {
   2051 			oal->next = al->next;
   2052 			alloc_xfree(al, sizeof (*al));
   2053 			return;
   2054 		}
   2055 	}
   2056 }
   2057 
   2058 static void
   2059 itree_prune_arrowlists(struct bubble *bubp)
   2060 {
   2061 	struct arrowlist *al, *nal;
   2062 
   2063 	al = bubp->arrows;
   2064 	while (al != NULL) {
   2065 		nal = al->next;
   2066 		if (bubp->t == B_FROM)
   2067 			itree_delete_arrow(al->arrowp->head, al->arrowp);
   2068 		else
   2069 			itree_delete_arrow(al->arrowp->tail, al->arrowp);
   2070 		itree_free_constraints(al->arrowp);
   2071 		alloc_xfree(al->arrowp, sizeof (struct arrow));
   2072 		alloc_xfree(al, sizeof (*al));
   2073 		al = nal;
   2074 	}
   2075 }
   2076 
   2077 struct arrowlist *
   2078 itree_next_arrow(struct bubble *bubble, struct arrowlist *last)
   2079 {
   2080 	struct arrowlist *next;
   2081 
   2082 	if (last != NULL)
   2083 		next = last->next;
   2084 	else
   2085 		next = bubble->arrows;
   2086 	return (next);
   2087 }
   2088 
   2089 static struct constraintlist *
   2090 itree_add_constraint(struct arrow *arrowp, struct node *c)
   2091 {
   2092 	struct constraintlist *prev = NULL;
   2093 	struct constraintlist *curr;
   2094 	struct constraintlist *newc;
   2095 
   2096 	for (curr = arrowp->constraints;
   2097 	    curr != NULL;
   2098 	    prev = curr, curr = curr->next)
   2099 		;
   2100 
   2101 	newc = alloc_xmalloc(sizeof (struct constraintlist));
   2102 	newc->next = NULL;
   2103 	newc->cnode = c;
   2104 
   2105 	if (prev == NULL)
   2106 		arrowp->constraints = newc;
   2107 	else
   2108 		prev->next = newc;
   2109 
   2110 	return (newc);
   2111 }
   2112 
   2113 struct constraintlist *
   2114 itree_next_constraint(struct arrow *arrowp, struct constraintlist *last)
   2115 {
   2116 	struct constraintlist *next;
   2117 
   2118 	if (last != NULL)
   2119 		next = last->next;
   2120 	else
   2121 		next = arrowp->constraints;
   2122 	return (next);
   2123 }
   2124 
   2125 static void
   2126 itree_free_constraints(struct arrow *ap)
   2127 {
   2128 	struct constraintlist *cl, *ncl;
   2129 
   2130 	cl = ap->constraints;
   2131 	while (cl != NULL) {
   2132 		ncl = cl->next;
   2133 		ASSERT(cl->cnode != NULL);
   2134 		if (!iexpr_cached(cl->cnode))
   2135 			tree_free(cl->cnode);
   2136 		else
   2137 			iexpr_free(cl->cnode);
   2138 		alloc_xfree(cl, sizeof (*cl));
   2139 		cl = ncl;
   2140 	}
   2141 }
   2142 
   2143 const char *
   2144 itree_bubbletype2str(enum bubbletype t)
   2145 {
   2146 	static char buf[100];
   2147 
   2148 	switch (t) {
   2149 	case B_FROM:	return L_from;
   2150 	case B_TO:	return L_to;
   2151 	case B_INHIBIT:	return L_inhibit;
   2152 	default:
   2153 		(void) sprintf(buf, "[unexpected bubbletype: %d]", t);
   2154 		return (buf);
   2155 	}
   2156 }
   2157 
   2158 /*
   2159  * itree_fini -- clean up any half-built itrees
   2160  */
   2161 void
   2162 itree_fini(void)
   2163 {
   2164 	if (Ninfo.lut != NULL) {
   2165 		itree_free(Ninfo.lut);
   2166 		Ninfo.lut = NULL;
   2167 	}
   2168 	if (Ninfo.ex) {
   2169 		lut_free(Ninfo.ex, iterinfo_destructor, NULL);
   2170 		Ninfo.ex = NULL;
   2171 	}
   2172 }
   2173