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