10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*186Sdb35262 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate * 260Sstevel@tonic-gate * itree.c -- instance tree creation and manipulation 270Sstevel@tonic-gate * 280Sstevel@tonic-gate * this module provides the instance tree 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <stdio.h> 340Sstevel@tonic-gate #include <ctype.h> 350Sstevel@tonic-gate #include <string.h> 360Sstevel@tonic-gate #include <strings.h> 370Sstevel@tonic-gate #include "alloc.h" 380Sstevel@tonic-gate #include "out.h" 390Sstevel@tonic-gate #include "stable.h" 400Sstevel@tonic-gate #include "literals.h" 410Sstevel@tonic-gate #include "lut.h" 420Sstevel@tonic-gate #include "tree.h" 430Sstevel@tonic-gate #include "ptree.h" 440Sstevel@tonic-gate #include "itree.h" 450Sstevel@tonic-gate #include "ipath.h" 460Sstevel@tonic-gate #include "eval.h" 470Sstevel@tonic-gate #include "config.h" 480Sstevel@tonic-gate 490Sstevel@tonic-gate /* 500Sstevel@tonic-gate * struct info contains the state we keep when expanding a prop statement 510Sstevel@tonic-gate * as part of constructing the instance tree. state kept in struct info 520Sstevel@tonic-gate * is the non-recursive stuff -- the stuff that doesn't need to be on 530Sstevel@tonic-gate * the stack. the rest of the state that is passed between all the 540Sstevel@tonic-gate * mutually recursive functions, is required to be on the stack since 550Sstevel@tonic-gate * we need to backtrack and recurse as we do the instance tree construction. 560Sstevel@tonic-gate */ 570Sstevel@tonic-gate struct info { 580Sstevel@tonic-gate struct lut *lut; 590Sstevel@tonic-gate struct node *anp; /* arrow np */ 600Sstevel@tonic-gate struct lut *ex; /* dictionary of explicit iterators */ 610Sstevel@tonic-gate struct config *croot; 620Sstevel@tonic-gate } Ninfo; 630Sstevel@tonic-gate 640Sstevel@tonic-gate /* 650Sstevel@tonic-gate * struct wildcardinfo is used to track wildcarded portions of paths. 660Sstevel@tonic-gate * 670Sstevel@tonic-gate * for example, if the epname of an event is "c/d" and the path "a/b/c/d" 680Sstevel@tonic-gate * exists, the wildcard path ewname is filled in with the path "a/b". when 690Sstevel@tonic-gate * matching is done, epname is temporarily replaced with the concatenation 700Sstevel@tonic-gate * of ewname and epname. cpstart is set to the (struct config *) 710Sstevel@tonic-gate * corresponding to component "c". 720Sstevel@tonic-gate * 730Sstevel@tonic-gate * a linked list of these structs is used to track the expansion of each 740Sstevel@tonic-gate * event node as it is processed in vmatch() --> vmatch_event() calls. 750Sstevel@tonic-gate */ 760Sstevel@tonic-gate struct wildcardinfo { 770Sstevel@tonic-gate struct node *nptop; /* event node fed to vmatch */ 780Sstevel@tonic-gate struct node *oldepname; /* epname without the wildcard part */ 790Sstevel@tonic-gate enum status { 800Sstevel@tonic-gate WC_UNDEFINED, /* struct is not yet initialized */ 810Sstevel@tonic-gate WC_UNDERCONSTRUCTION, /* wildcard path not yet done */ 82*186Sdb35262 WC_COMPLETE /* wildcard path done and is in use */ 830Sstevel@tonic-gate } s; 840Sstevel@tonic-gate struct wildcardpath { 850Sstevel@tonic-gate struct node *ewname; /* wildcard path */ 860Sstevel@tonic-gate struct config *cpstart; /* starting cp node for oldepname */ 870Sstevel@tonic-gate int refcount; /* number of event nodes using this */ 880Sstevel@tonic-gate } *p; 89*186Sdb35262 struct wildcardpath *matchwc; /* ptr to wc path to be matched */ 900Sstevel@tonic-gate struct wildcardinfo *next; 910Sstevel@tonic-gate }; 920Sstevel@tonic-gate 930Sstevel@tonic-gate static void vmatch(struct info *infop, struct node *np, 940Sstevel@tonic-gate struct node *lnp, struct node *anp, struct wildcardinfo **wcproot); 950Sstevel@tonic-gate static void hmatch(struct info *infop, struct node *np, struct node *nextnp); 960Sstevel@tonic-gate static void itree_pbubble(int flags, struct bubble *bp); 970Sstevel@tonic-gate static void itree_destructor(void *left, void *right, void *arg); 980Sstevel@tonic-gate static int itree_set_arrow_traits(struct arrow *ap, struct node *fromev, 990Sstevel@tonic-gate struct node *toev, struct lut *ex); 1000Sstevel@tonic-gate static void itree_free_arrowlists(struct bubble *bubp, int arrows_too); 1010Sstevel@tonic-gate static void arrow_add_within(struct arrow *ap, struct node *xpr); 1020Sstevel@tonic-gate static struct arrow *itree_add_arrow(struct bubble *frombubblep, 1030Sstevel@tonic-gate struct bubble *tobubblep, struct node *apnode, struct node *fromevent, 1040Sstevel@tonic-gate struct node *toevent, struct lut *ex); 1050Sstevel@tonic-gate static struct constraintlist *itree_add_constraint(struct arrow *arrowp, 1060Sstevel@tonic-gate struct node *c); 1070Sstevel@tonic-gate static struct bubble *itree_add_bubble(struct event *eventp, 1080Sstevel@tonic-gate enum bubbletype btype, int nork, int gen); 1090Sstevel@tonic-gate static void itree_free_bubble(struct bubble *freeme); 1100Sstevel@tonic-gate static void itree_free_constraints(struct arrow *ap); 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate /* 1130Sstevel@tonic-gate * the following struct contains the state we build up during 1140Sstevel@tonic-gate * vertical and horizontal expansion so that generate() 1150Sstevel@tonic-gate * has everything it needs to construct the appropriate arrows. 1160Sstevel@tonic-gate * after setting up the state by calling: 1170Sstevel@tonic-gate * generate_arrownp() 1180Sstevel@tonic-gate * generate_nork() 1190Sstevel@tonic-gate * generate_new() 1200Sstevel@tonic-gate * generate_from() 1210Sstevel@tonic-gate * generate_to() 1220Sstevel@tonic-gate * the actual arrow generation is done by calling: 1230Sstevel@tonic-gate * generate() 1240Sstevel@tonic-gate */ 1250Sstevel@tonic-gate static struct { 1260Sstevel@tonic-gate int generation; /* generation number of arrow set */ 1270Sstevel@tonic-gate struct node *arrownp; /* top-level parse tree for arrow */ 1280Sstevel@tonic-gate int n; /* n value associated with arrow */ 1290Sstevel@tonic-gate int k; /* k value associated with arrow */ 1300Sstevel@tonic-gate struct node *fromnp; /* left-hand-side event in parse tree */ 1310Sstevel@tonic-gate struct node *tonp; /* right-hand-side event in parse tree */ 1320Sstevel@tonic-gate struct event *frome; /* left-hand-side event in instance tree */ 1330Sstevel@tonic-gate struct event *toe; /* right-hand-side event in instance tree */ 1340Sstevel@tonic-gate struct bubble *frombp; /* bubble arrow comes from */ 1350Sstevel@tonic-gate struct bubble *tobp; /* bubble arrow goes to */ 1360Sstevel@tonic-gate } G; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate static void 1390Sstevel@tonic-gate generate_arrownp(struct node *arrownp) 1400Sstevel@tonic-gate { 1410Sstevel@tonic-gate G.arrownp = arrownp; 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate static void 1450Sstevel@tonic-gate generate_nork(int n, int k) 1460Sstevel@tonic-gate { 1470Sstevel@tonic-gate G.n = n; 1480Sstevel@tonic-gate G.k = k; 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate static void 1520Sstevel@tonic-gate generate_new(void) 1530Sstevel@tonic-gate { 1540Sstevel@tonic-gate G.generation++; 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate static void 1580Sstevel@tonic-gate generate_from(struct node *fromeventnp, struct event *fromevent) 1590Sstevel@tonic-gate { 1600Sstevel@tonic-gate G.fromnp = fromeventnp; 1610Sstevel@tonic-gate G.frome = fromevent; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate out(O_ALTFP|O_VERB3|O_NONL, "from bubble on "); 1640Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp); 1650Sstevel@tonic-gate out(O_ALTFP|O_VERB3, NULL); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate G.frombp = itree_add_bubble(G.frome, B_FROM, G.n, 0); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate static void 1710Sstevel@tonic-gate generate_to(struct node *toeventnp, struct event *toevent) 1720Sstevel@tonic-gate { 1730Sstevel@tonic-gate G.tonp = toeventnp; 1740Sstevel@tonic-gate G.toe = toevent; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate out(O_ALTFP|O_VERB3|O_NONL, "to bubble (gen %d) on ", G.generation); 1770Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp); 1780Sstevel@tonic-gate out(O_ALTFP|O_VERB3, NULL); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate G.tobp = itree_add_bubble(G.toe, B_TO, G.k, G.generation); 1810Sstevel@tonic-gate } 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate static void 1840Sstevel@tonic-gate generate(struct lut *ex) 1850Sstevel@tonic-gate { 1860Sstevel@tonic-gate ASSERT(G.arrownp != NULL); 1870Sstevel@tonic-gate ASSERT(G.fromnp != NULL); 1880Sstevel@tonic-gate ASSERT(G.frome != NULL); 1890Sstevel@tonic-gate ASSERT(G.frombp != NULL); 1900Sstevel@tonic-gate ASSERT(G.tonp != NULL); 1910Sstevel@tonic-gate ASSERT(G.toe != NULL); 1920Sstevel@tonic-gate ASSERT(G.tobp != NULL); 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate out(O_ALTFP|O_VERB3|O_NONL, " Arrow \""); 1950Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp); 1960Sstevel@tonic-gate out(O_ALTFP|O_VERB3|O_NONL, "\" -> \""); 1970Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp); 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate if (itree_add_arrow(G.frombp, G.tobp, G.arrownp, 2000Sstevel@tonic-gate G.fromnp, G.tonp, ex) == NULL) { 2010Sstevel@tonic-gate out(O_ALTFP|O_VERB3, "\" (prevented by constraints)"); 2020Sstevel@tonic-gate } else { 2030Sstevel@tonic-gate out(O_ALTFP|O_VERB3, "\""); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate enum childnode_action { 2080Sstevel@tonic-gate CN_NONE, 2090Sstevel@tonic-gate CN_INSTANTIZE, 2100Sstevel@tonic-gate CN_DUP 2110Sstevel@tonic-gate }; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate static struct node * 2140Sstevel@tonic-gate tname_dup(struct node *namep, enum childnode_action act) 2150Sstevel@tonic-gate { 2160Sstevel@tonic-gate struct node *retp = NULL; 2170Sstevel@tonic-gate const char *file; 2180Sstevel@tonic-gate int line; 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate if (namep == NULL) 2210Sstevel@tonic-gate return (NULL); 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate file = namep->file; 2240Sstevel@tonic-gate line = namep->line; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate for (; namep != NULL; namep = namep->u.name.next) { 2270Sstevel@tonic-gate struct node *newnp = newnode(T_NAME, file, line); 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate newnp->u.name.t = namep->u.name.t; 2300Sstevel@tonic-gate newnp->u.name.s = namep->u.name.s; 2310Sstevel@tonic-gate newnp->u.name.last = newnp; 2320Sstevel@tonic-gate newnp->u.name.it = namep->u.name.it; 2330Sstevel@tonic-gate newnp->u.name.cp = namep->u.name.cp; 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate if (act == CN_DUP) { 2360Sstevel@tonic-gate struct node *npc; 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate npc = namep->u.name.child; 2390Sstevel@tonic-gate if (npc != NULL) { 2400Sstevel@tonic-gate switch (npc->t) { 2410Sstevel@tonic-gate case T_NUM: 2420Sstevel@tonic-gate newnp->u.name.child = 2430Sstevel@tonic-gate newnode(T_NUM, file, line); 2440Sstevel@tonic-gate newnp->u.name.child->u.ull = 2450Sstevel@tonic-gate npc->u.ull; 2460Sstevel@tonic-gate break; 2470Sstevel@tonic-gate case T_NAME: 2480Sstevel@tonic-gate newnp->u.name.child = 2490Sstevel@tonic-gate tree_name(npc->u.name.s, 2500Sstevel@tonic-gate npc->u.name.it, 2510Sstevel@tonic-gate file, line); 2520Sstevel@tonic-gate break; 2530Sstevel@tonic-gate default: 2540Sstevel@tonic-gate out(O_DIE, "tname_dup: " 2550Sstevel@tonic-gate "invalid child type %s", 2560Sstevel@tonic-gate ptree_nodetype2str(npc->t)); 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate } else if (act == CN_INSTANTIZE) { 2600Sstevel@tonic-gate newnp->u.name.child = newnode(T_NUM, file, line); 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate if (namep->u.name.child == NULL || 2630Sstevel@tonic-gate namep->u.name.child->t != T_NUM) { 2640Sstevel@tonic-gate int inum; 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate ASSERT(newnp->u.name.cp != NULL); 2670Sstevel@tonic-gate config_getcompname(newnp->u.name.cp, 2680Sstevel@tonic-gate NULL, &inum); 2690Sstevel@tonic-gate newnp->u.name.child->u.ull = 2700Sstevel@tonic-gate (unsigned long long)inum; 2710Sstevel@tonic-gate } else { 2720Sstevel@tonic-gate newnp->u.name.child->u.ull = 2730Sstevel@tonic-gate namep->u.name.child->u.ull; 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate if (retp == NULL) { 2780Sstevel@tonic-gate retp = newnp; 2790Sstevel@tonic-gate } else { 2800Sstevel@tonic-gate retp->u.name.last->u.name.next = newnp; 2810Sstevel@tonic-gate retp->u.name.last = newnp; 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate return (retp); 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate struct prop_wlk_data { 2890Sstevel@tonic-gate struct lut *props; 2900Sstevel@tonic-gate struct node *epname; 2910Sstevel@tonic-gate }; 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate static struct lut *props2instance(struct node *, struct node *); 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate /* 2960Sstevel@tonic-gate * let oldepname be a subset of epname. return the subsection of epname 2970Sstevel@tonic-gate * that ends with oldepname. make each component in the path explicitly 2980Sstevel@tonic-gate * instanced (i.e., with a T_NUM child). 2990Sstevel@tonic-gate */ 3000Sstevel@tonic-gate static struct node * 3010Sstevel@tonic-gate tname_dup_to_epname(struct node *oldepname, struct node *epname) 3020Sstevel@tonic-gate { 3030Sstevel@tonic-gate struct node *npref, *npend, *np1, *np2; 3040Sstevel@tonic-gate struct node *ret = NULL; 3050Sstevel@tonic-gate int foundmatch = 0; 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate if (epname == NULL) 3080Sstevel@tonic-gate return (NULL); 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate /* 3110Sstevel@tonic-gate * search for the longest path in epname which contains 3120Sstevel@tonic-gate * oldnode->u.event.epname. set npend to point to just past the 3130Sstevel@tonic-gate * end of this path. 3140Sstevel@tonic-gate */ 3150Sstevel@tonic-gate npend = NULL; 3160Sstevel@tonic-gate for (npref = epname; npref; npref = npref->u.name.next) { 3170Sstevel@tonic-gate if (npref->u.name.s == oldepname->u.name.s) { 3180Sstevel@tonic-gate for (np1 = npref, np2 = oldepname; 3190Sstevel@tonic-gate np1 != NULL && np2 != NULL; 3200Sstevel@tonic-gate np1 = np1->u.name.next, np2 = np2->u.name.next) { 3210Sstevel@tonic-gate if (np1->u.name.s != np2->u.name.s) 3220Sstevel@tonic-gate break; 3230Sstevel@tonic-gate } 3240Sstevel@tonic-gate if (np2 == NULL) { 3250Sstevel@tonic-gate foundmatch = 1; 3260Sstevel@tonic-gate npend = np1; 3270Sstevel@tonic-gate if (np1 == NULL) { 3280Sstevel@tonic-gate /* oldepname matched npref up to end */ 3290Sstevel@tonic-gate break; 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate if (foundmatch == 0) { 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * if oldepname could not be found in epname, return a 3380Sstevel@tonic-gate * duplicate of the former. do not try to instantize 3390Sstevel@tonic-gate * oldepname since it might not be a path. 3400Sstevel@tonic-gate */ 3410Sstevel@tonic-gate return (tname_dup(oldepname, CN_DUP)); 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate /* 3450Sstevel@tonic-gate * dup (epname -- npend). all children should be T_NUMs. 3460Sstevel@tonic-gate */ 3470Sstevel@tonic-gate for (npref = epname; 3480Sstevel@tonic-gate ! (npref == NULL || npref == npend); 3490Sstevel@tonic-gate npref = npref->u.name.next) { 3500Sstevel@tonic-gate struct node *newnp = newnode(T_NAME, oldepname->file, 3510Sstevel@tonic-gate oldepname->line); 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate newnp->u.name.t = npref->u.name.t; 3540Sstevel@tonic-gate newnp->u.name.s = npref->u.name.s; 3550Sstevel@tonic-gate newnp->u.name.last = newnp; 3560Sstevel@tonic-gate newnp->u.name.it = npref->u.name.it; 3570Sstevel@tonic-gate newnp->u.name.cp = npref->u.name.cp; 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate newnp->u.name.child = newnode(T_NUM, oldepname->file, 3600Sstevel@tonic-gate oldepname->line); 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate if (npref->u.name.child == NULL || 3630Sstevel@tonic-gate npref->u.name.child->t != T_NUM) { 3640Sstevel@tonic-gate int childnum; 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate ASSERT(npref->u.name.cp != NULL); 3670Sstevel@tonic-gate config_getcompname(npref->u.name.cp, NULL, &childnum); 3680Sstevel@tonic-gate newnp->u.name.child->u.ull = childnum; 3690Sstevel@tonic-gate } else { 3700Sstevel@tonic-gate newnp->u.name.child->u.ull = 3710Sstevel@tonic-gate npref->u.name.child->u.ull; 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate if (ret == NULL) { 3750Sstevel@tonic-gate ret = newnp; 3760Sstevel@tonic-gate } else { 3770Sstevel@tonic-gate ret->u.name.last->u.name.next = newnp; 3780Sstevel@tonic-gate ret->u.name.last = newnp; 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate return (ret); 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate /* 3860Sstevel@tonic-gate * restriction: oldnode->u.event.epname has to be equivalent to or a subset 3870Sstevel@tonic-gate * of epname 3880Sstevel@tonic-gate */ 3890Sstevel@tonic-gate static struct node * 3900Sstevel@tonic-gate tevent_dup_to_epname(struct node *oldnode, struct node *epname) 3910Sstevel@tonic-gate { 3920Sstevel@tonic-gate struct node *ret; 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate ret = newnode(T_EVENT, oldnode->file, oldnode->line); 3950Sstevel@tonic-gate ret->u.event.ename = tname_dup(oldnode->u.event.ename, CN_NONE); 3960Sstevel@tonic-gate ret->u.event.epname = tname_dup_to_epname(oldnode->u.event.epname, 3970Sstevel@tonic-gate epname); 3980Sstevel@tonic-gate return (ret); 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate static void 4020Sstevel@tonic-gate nv_instantiate(void *name, void *val, void *arg) 4030Sstevel@tonic-gate { 4040Sstevel@tonic-gate struct prop_wlk_data *pd = (struct prop_wlk_data *)arg; 4050Sstevel@tonic-gate struct node *orhs = (struct node *)val; 4060Sstevel@tonic-gate struct node *nrhs; 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate /* handle engines by instantizing the entire engine */ 4090Sstevel@tonic-gate if (name == L_engine) { 4100Sstevel@tonic-gate ASSERT(orhs->t == T_EVENT); 4110Sstevel@tonic-gate ASSERT(orhs->u.event.ename->u.name.t == N_SERD); 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate /* there are only SERD engines for now */ 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate nrhs = newnode(T_SERD, orhs->file, orhs->line); 4160Sstevel@tonic-gate nrhs->u.stmt.np = tevent_dup_to_epname(orhs, pd->epname); 4170Sstevel@tonic-gate nrhs->u.stmt.lutp = props2instance(orhs, pd->epname); 4180Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL); 4190Sstevel@tonic-gate return; 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate switch (orhs->t) { 4230Sstevel@tonic-gate case T_NUM: 4240Sstevel@tonic-gate nrhs = newnode(T_NUM, orhs->file, orhs->line); 4250Sstevel@tonic-gate nrhs->u.ull = orhs->u.ull; 4260Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL); 4270Sstevel@tonic-gate break; 4280Sstevel@tonic-gate case T_TIMEVAL: 4290Sstevel@tonic-gate nrhs = newnode(T_TIMEVAL, orhs->file, orhs->line); 4300Sstevel@tonic-gate nrhs->u.ull = orhs->u.ull; 4310Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL); 4320Sstevel@tonic-gate break; 4330Sstevel@tonic-gate case T_NAME: 4340Sstevel@tonic-gate nrhs = tname_dup_to_epname(orhs, pd->epname); 4350Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL); 4360Sstevel@tonic-gate break; 4370Sstevel@tonic-gate case T_EVENT: 4380Sstevel@tonic-gate nrhs = tevent_dup_to_epname(orhs, pd->epname); 4390Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL); 4400Sstevel@tonic-gate break; 4410Sstevel@tonic-gate default: 4420Sstevel@tonic-gate out(O_DEBUG, "unexpected nvpair value type %s", 4430Sstevel@tonic-gate ptree_nodetype2str(((struct node *)val)->t)); 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate static struct lut * 4480Sstevel@tonic-gate props2instance(struct node *eventnp, struct node *epname) 4490Sstevel@tonic-gate { 4500Sstevel@tonic-gate struct prop_wlk_data pd; 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate pd.props = NULL; 4530Sstevel@tonic-gate pd.epname = epname; 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate ASSERT(eventnp->u.event.declp != NULL); 4560Sstevel@tonic-gate lut_walk(eventnp->u.event.declp->u.stmt.lutp, nv_instantiate, &pd); 4570Sstevel@tonic-gate return (pd.props); 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate /*ARGSUSED*/ 4610Sstevel@tonic-gate static void 4620Sstevel@tonic-gate instances_destructor(void *left, void *right, void *arg) 4630Sstevel@tonic-gate { 4640Sstevel@tonic-gate struct node *dn = (struct node *)right; 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate if (dn->t == T_SERD) { 4670Sstevel@tonic-gate /* we allocated the lut during itree_create(), so free it */ 4680Sstevel@tonic-gate lut_free(dn->u.stmt.lutp, instances_destructor, NULL); 4690Sstevel@tonic-gate dn->u.stmt.lutp = NULL; 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate tree_free(dn); 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate /* 4750Sstevel@tonic-gate * event_cmp -- used via lut_lookup/lut_add on instance tree lut 4760Sstevel@tonic-gate */ 4770Sstevel@tonic-gate static int 4780Sstevel@tonic-gate event_cmp(struct event *ep1, struct event *ep2) 4790Sstevel@tonic-gate { 4800Sstevel@tonic-gate int diff; 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate if ((diff = ep2->enode->u.event.ename->u.name.s - 4830Sstevel@tonic-gate ep1->enode->u.event.ename->u.name.s) != 0) 4840Sstevel@tonic-gate return (diff); 4850Sstevel@tonic-gate if ((diff = (char *)ep2->ipp - (char *)ep1->ipp) != 0) 4860Sstevel@tonic-gate return (diff); 4870Sstevel@tonic-gate return (0); 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate struct event * 4920Sstevel@tonic-gate itree_lookup(struct lut *itp, const char *ename, const struct ipath *ipp) 4930Sstevel@tonic-gate { 4940Sstevel@tonic-gate struct event searchevent; /* just used for searching */ 4950Sstevel@tonic-gate struct node searcheventnode; 4960Sstevel@tonic-gate struct node searchenamenode; 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate searchevent.enode = &searcheventnode; 4990Sstevel@tonic-gate searcheventnode.t = T_EVENT; 5000Sstevel@tonic-gate searcheventnode.u.event.ename = &searchenamenode; 5010Sstevel@tonic-gate searchenamenode.t = T_NAME; 5020Sstevel@tonic-gate searchenamenode.u.name.s = ename; 5030Sstevel@tonic-gate searchevent.ipp = ipp; 5040Sstevel@tonic-gate return (lut_lookup(itp, (void *)&searchevent, (lut_cmp)event_cmp)); 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate static struct event * 5080Sstevel@tonic-gate find_or_add_event(struct info *infop, struct node *np) 5090Sstevel@tonic-gate { 5100Sstevel@tonic-gate struct event *ret; 5110Sstevel@tonic-gate struct event searchevent; /* just used for searching */ 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate ASSERTeq(np->t, T_EVENT, ptree_nodetype2str); 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate searchevent.enode = np; 5160Sstevel@tonic-gate searchevent.ipp = ipath(np->u.event.epname); 5170Sstevel@tonic-gate if ((ret = lut_lookup(infop->lut, (void *)&searchevent, 5180Sstevel@tonic-gate (lut_cmp)event_cmp)) != NULL) 5190Sstevel@tonic-gate return (ret); 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate /* wasn't already in tree, allocate it */ 5220Sstevel@tonic-gate ret = MALLOC(sizeof (*ret)); 5230Sstevel@tonic-gate bzero(ret, sizeof (*ret)); 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate ret->t = np->u.event.ename->u.name.t; 5260Sstevel@tonic-gate ret->enode = np; 5270Sstevel@tonic-gate ret->ipp = searchevent.ipp; 5280Sstevel@tonic-gate ret->props = props2instance(np, np->u.event.epname); 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate infop->lut = lut_add(infop->lut, (void *)ret, (void *)ret, 5310Sstevel@tonic-gate (lut_cmp)event_cmp); 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate return (ret); 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate /* 5370Sstevel@tonic-gate * hmatch_event -- perform any appropriate horizontal expansion on an event 5380Sstevel@tonic-gate * 5390Sstevel@tonic-gate * this routine is used to perform horizontal expansion on both the 5400Sstevel@tonic-gate * left-hand-side events in a prop, and the right-hand-side events. 5410Sstevel@tonic-gate * when called to handle a left-side event, nextnp point to the right 5420Sstevel@tonic-gate * side of the prop that should be passed to hmatch() for each match 5430Sstevel@tonic-gate * found by horizontal expansion. when no horizontal expansion exists, 5440Sstevel@tonic-gate * we will still "match" one event for every event found in the list on 5450Sstevel@tonic-gate * the left-hand-side of the prop because vmatch() already found that 5460Sstevel@tonic-gate * there's at least one match during vertical expansion. 5470Sstevel@tonic-gate */ 5480Sstevel@tonic-gate static void 5490Sstevel@tonic-gate hmatch_event(struct info *infop, struct node *eventnp, struct node *epname, 5500Sstevel@tonic-gate struct config *ncp, struct node *nextnp, int rematch) 5510Sstevel@tonic-gate { 5520Sstevel@tonic-gate if (epname == NULL) { 5530Sstevel@tonic-gate /* 5540Sstevel@tonic-gate * end of pathname recursion, either we just located 5550Sstevel@tonic-gate * a left-hand-side event and we're ready to move on 5560Sstevel@tonic-gate * to the expanding the right-hand-side events, or 5570Sstevel@tonic-gate * we're further down the recursion and we just located 5580Sstevel@tonic-gate * a right-hand-side event. the passed-in parameter 5590Sstevel@tonic-gate * "nextnp" tells us whether we're working on the left 5600Sstevel@tonic-gate * side and need to move on to nextnp, or if nextnp is 5610Sstevel@tonic-gate * NULL, we're working on the right side. 5620Sstevel@tonic-gate */ 5630Sstevel@tonic-gate if (nextnp) { 5640Sstevel@tonic-gate /* 5650Sstevel@tonic-gate * finished a left side expansion, move on to right. 5660Sstevel@tonic-gate * tell generate() what event we just matched so 5670Sstevel@tonic-gate * it can be used at the source of any arrows 5680Sstevel@tonic-gate * we generate as we match events on the right side. 5690Sstevel@tonic-gate */ 5700Sstevel@tonic-gate generate_from(eventnp, 5710Sstevel@tonic-gate find_or_add_event(infop, eventnp)); 5720Sstevel@tonic-gate hmatch(infop, nextnp, NULL); 5730Sstevel@tonic-gate } else { 5740Sstevel@tonic-gate /* 5750Sstevel@tonic-gate * finished a right side expansion. tell generate 5760Sstevel@tonic-gate * the information about the destination and let 5770Sstevel@tonic-gate * it construct the arrows as appropriate. 5780Sstevel@tonic-gate */ 5790Sstevel@tonic-gate generate_to(eventnp, 5800Sstevel@tonic-gate find_or_add_event(infop, eventnp)); 5810Sstevel@tonic-gate generate(infop->ex); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate return; 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate ASSERTeq(epname->t, T_NAME, ptree_nodetype2str); 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate /* 5900Sstevel@tonic-gate * we only get here when eventnp already has a completely 5910Sstevel@tonic-gate * instanced epname in it already. so we first recurse 5920Sstevel@tonic-gate * down to the end of the name and as the recursion pops 5930Sstevel@tonic-gate * up, we look for opportunities to advance horizontal 5940Sstevel@tonic-gate * expansions on to the next match. when we do advance 5950Sstevel@tonic-gate * horizontal expansions, we potentially render all cp 5960Sstevel@tonic-gate * pointers on all components to the right as invalid, 5970Sstevel@tonic-gate * so we pass in an "ncp" config handle so matching against 5980Sstevel@tonic-gate * the config can happen. 5990Sstevel@tonic-gate */ 6000Sstevel@tonic-gate if (rematch) { 6010Sstevel@tonic-gate struct config *ocp = epname->u.name.cp; 6020Sstevel@tonic-gate char *ncp_s; 6030Sstevel@tonic-gate int ncp_num, num; 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate for (; ncp; ncp = config_next(ncp)) { 6060Sstevel@tonic-gate config_getcompname(ncp, &ncp_s, &ncp_num); 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate if (ncp_s == epname->u.name.s) { 6090Sstevel@tonic-gate /* found a matching component name */ 6100Sstevel@tonic-gate config_getcompname(epname->u.name.cp, 6110Sstevel@tonic-gate NULL, &num); 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate if (epname->u.name.it != IT_HORIZONTAL && 6140Sstevel@tonic-gate ncp_num != num) 6150Sstevel@tonic-gate continue; 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate epname->u.name.cp = ncp; 6180Sstevel@tonic-gate hmatch_event(infop, eventnp, 6190Sstevel@tonic-gate epname->u.name.next, config_child(ncp), 6200Sstevel@tonic-gate nextnp, 1); 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate epname->u.name.cp = ocp; 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate return; /* no more config to match against */ 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate } else { 6290Sstevel@tonic-gate hmatch_event(infop, eventnp, epname->u.name.next, ncp, 6300Sstevel@tonic-gate nextnp, 0); 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate if (epname->u.name.it == IT_HORIZONTAL) { 6340Sstevel@tonic-gate struct config *cp; 6350Sstevel@tonic-gate struct config *ocp = epname->u.name.cp; 6360Sstevel@tonic-gate char *cp_s; 6370Sstevel@tonic-gate int cp_num; 6380Sstevel@tonic-gate int ocp_num; 6390Sstevel@tonic-gate struct iterinfo *iterinfop = NULL; 6400Sstevel@tonic-gate const char *iters; 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate config_getcompname(ocp, NULL, &ocp_num); 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate for (cp = config_next(ocp); cp; cp = config_next(cp)) { 6450Sstevel@tonic-gate config_getcompname(cp, &cp_s, &cp_num); 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate if (cp_s == epname->u.name.s) { 6480Sstevel@tonic-gate ASSERT(epname->u.name.child != NULL); 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate iters = epname->u.name.child->u.name.s; 6510Sstevel@tonic-gate if ((iterinfop = lut_lookup(infop->ex, 6520Sstevel@tonic-gate (void *)iters, NULL)) == NULL) { 6530Sstevel@tonic-gate out(O_DIE, 6540Sstevel@tonic-gate "hmatch_event: internal error: " 6550Sstevel@tonic-gate "iterator \"%s\" undefined", iters); 6560Sstevel@tonic-gate } else { 6570Sstevel@tonic-gate /* advance dict entry to next match */ 6580Sstevel@tonic-gate iterinfop->num = cp_num; 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate epname->u.name.cp = cp; 6610Sstevel@tonic-gate hmatch_event(infop, eventnp, 6620Sstevel@tonic-gate epname->u.name.next, config_child(cp), 6630Sstevel@tonic-gate nextnp, 1); 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate if (iterinfop != NULL) { 6680Sstevel@tonic-gate /* restore dict entry */ 6690Sstevel@tonic-gate iterinfop->num = ocp_num; 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate epname->u.name.cp = ocp; 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate /* 6760Sstevel@tonic-gate * hmatch -- check for horizontal expansion matches 6770Sstevel@tonic-gate * 6780Sstevel@tonic-gate * np points to the things we're matching (like a T_LIST or a T_EVENT) 6790Sstevel@tonic-gate * and if we're working on a left-side of a prop, nextnp points to 6800Sstevel@tonic-gate * the other side of the prop that we'll tackle next when this recursion 6810Sstevel@tonic-gate * bottoms out. when all the events in the entire prop arrow have been 6820Sstevel@tonic-gate * horizontally expanded, generate() will be called to generate the 6830Sstevel@tonic-gate * actualy arrow. 6840Sstevel@tonic-gate */ 6850Sstevel@tonic-gate static void 6860Sstevel@tonic-gate hmatch(struct info *infop, struct node *np, struct node *nextnp) 6870Sstevel@tonic-gate { 6880Sstevel@tonic-gate if (np == NULL) 6890Sstevel@tonic-gate return; /* all done */ 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate /* 6920Sstevel@tonic-gate * for each item in the list of events (which could just 6930Sstevel@tonic-gate * be a single event, or it could get larger in the loop 6940Sstevel@tonic-gate * below due to horizontal expansion), call hmatch on 6950Sstevel@tonic-gate * the right side and create arrows to each element. 6960Sstevel@tonic-gate */ 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate switch (np->t) { 6990Sstevel@tonic-gate case T_LIST: 7000Sstevel@tonic-gate /* loop through the list */ 7010Sstevel@tonic-gate if (np->u.expr.left) 7020Sstevel@tonic-gate hmatch(infop, np->u.expr.left, nextnp); 7030Sstevel@tonic-gate if (np->u.expr.right) 7040Sstevel@tonic-gate hmatch(infop, np->u.expr.right, nextnp); 7050Sstevel@tonic-gate break; 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate case T_EVENT: 7080Sstevel@tonic-gate hmatch_event(infop, np, np->u.event.epname, 7090Sstevel@tonic-gate NULL, nextnp, 0); 7100Sstevel@tonic-gate break; 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate default: 7130Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 7140Sstevel@tonic-gate "hmatch: unexpected type: %s", 7150Sstevel@tonic-gate ptree_nodetype2str(np->t)); 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate static int 7200Sstevel@tonic-gate itree_np2nork(struct node *norknp) 7210Sstevel@tonic-gate { 7220Sstevel@tonic-gate if (norknp == NULL) 7230Sstevel@tonic-gate return (1); 7240Sstevel@tonic-gate else if (norknp->t == T_NAME && norknp->u.name.s == L_A) 7250Sstevel@tonic-gate return (-1); /* our internal version of "all" */ 7260Sstevel@tonic-gate else if (norknp->t == T_NUM) 7270Sstevel@tonic-gate return ((int)norknp->u.ull); 7280Sstevel@tonic-gate else 7290Sstevel@tonic-gate out(O_DIE, norknp->file, norknp->line, 7300Sstevel@tonic-gate "itree_np2nork: internal error type %s", 7310Sstevel@tonic-gate ptree_nodetype2str(norknp->t)); 7320Sstevel@tonic-gate /*NOTREACHED*/ 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate static struct iterinfo * 7360Sstevel@tonic-gate newiterinfo(int num, struct node *np) 7370Sstevel@tonic-gate { 7380Sstevel@tonic-gate struct iterinfo *ret = MALLOC(sizeof (*ret)); 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate ret->num = num; 7410Sstevel@tonic-gate ret->np = np; 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate return (ret); 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate /*ARGSUSED*/ 7470Sstevel@tonic-gate static void 7480Sstevel@tonic-gate iterinfo_destructor(void *left, void *right, void *arg) 7490Sstevel@tonic-gate { 7500Sstevel@tonic-gate struct iterinfo *iterinfop = (struct iterinfo *)right; 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate bzero(iterinfop, sizeof (*iterinfop)); 7530Sstevel@tonic-gate FREE(iterinfop); 7540Sstevel@tonic-gate } 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate /* 757*186Sdb35262 * return 1 if wildcard path for wcp matches another wildcard path; 758*186Sdb35262 * return 0 if otherwise. 759*186Sdb35262 */ 760*186Sdb35262 static int 761*186Sdb35262 wc_paths_match(struct wildcardinfo *wcp) 762*186Sdb35262 { 763*186Sdb35262 struct node *np1, *np2; 764*186Sdb35262 765*186Sdb35262 ASSERT(wcp->matchwc != NULL); 766*186Sdb35262 767*186Sdb35262 for (np1 = wcp->p->ewname, np2 = wcp->matchwc->ewname; 768*186Sdb35262 np1 != NULL && np2 != NULL; 769*186Sdb35262 np1 = np1->u.name.next, np2 = np2->u.name.next) { 770*186Sdb35262 /* 771*186Sdb35262 * names must match 772*186Sdb35262 */ 773*186Sdb35262 if (np1->u.name.s != np2->u.name.s) 774*186Sdb35262 return (0); 775*186Sdb35262 776*186Sdb35262 /* 777*186Sdb35262 * children must exist and have the same numerical value 778*186Sdb35262 */ 779*186Sdb35262 if (np1->u.name.child == NULL || np2->u.name.child == NULL) 780*186Sdb35262 return (0); 781*186Sdb35262 782*186Sdb35262 if (np1->u.name.child->t != T_NUM || 783*186Sdb35262 np2->u.name.child->t != T_NUM) 784*186Sdb35262 return (0); 785*186Sdb35262 786*186Sdb35262 if (np1->u.name.child->u.ull != np2->u.name.child->u.ull) 787*186Sdb35262 return (0); 788*186Sdb35262 } 789*186Sdb35262 790*186Sdb35262 /* 791*186Sdb35262 * return true only if we have matches for all entries of n1 and 792*186Sdb35262 * n2. note that NULL wildcard paths (i.e., both wcp->p->ewname 793*186Sdb35262 * and wcp->matchwc->ewname are NULL) will be considered as 794*186Sdb35262 * matching paths. 795*186Sdb35262 */ 796*186Sdb35262 if (np1 == NULL && np2 == NULL) 797*186Sdb35262 return (1); 798*186Sdb35262 799*186Sdb35262 return (0); 800*186Sdb35262 } 801*186Sdb35262 802*186Sdb35262 /* 8030Sstevel@tonic-gate * update epname to include the wildcarded portion 8040Sstevel@tonic-gate */ 8050Sstevel@tonic-gate static void 8060Sstevel@tonic-gate create_wildcardedpath(struct wildcardinfo **wcproot) 8070Sstevel@tonic-gate { 8080Sstevel@tonic-gate struct wildcardinfo *wcp; 8090Sstevel@tonic-gate struct node *nptop; 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate wcp = *wcproot; 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate if (wcp->s == WC_UNDERCONSTRUCTION) { 8140Sstevel@tonic-gate ASSERT(wcp->p->refcount == 1); 8150Sstevel@tonic-gate wcp->s = WC_COMPLETE; 8160Sstevel@tonic-gate } 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate /* path has no wildcard */ 8190Sstevel@tonic-gate if (wcp->p->ewname == NULL) 8200Sstevel@tonic-gate return; 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate /* 8230Sstevel@tonic-gate * get to this point if a wildcard portion of the path exists. 8240Sstevel@tonic-gate * 8250Sstevel@tonic-gate * first set oldepname to the start of the existing epname for use 8260Sstevel@tonic-gate * in future comparisons, then update epname to include the 8270Sstevel@tonic-gate * wildcard portion. 8280Sstevel@tonic-gate */ 8290Sstevel@tonic-gate nptop = wcp->nptop; 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate ASSERT(wcp->oldepname == nptop->u.event.epname); 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate nptop->u.event.epname = tname_dup(wcp->p->ewname, CN_DUP); 8340Sstevel@tonic-gate nptop->u.event.epname = tree_name_append(nptop->u.event.epname, 8350Sstevel@tonic-gate tname_dup(wcp->oldepname, CN_DUP)); 8360Sstevel@tonic-gate } 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate /* 8390Sstevel@tonic-gate * restore epname to its former (nonwildcarded) state 8400Sstevel@tonic-gate */ 8410Sstevel@tonic-gate static void 8420Sstevel@tonic-gate undo_wildcardedpath(struct wildcardinfo **wcproot) 8430Sstevel@tonic-gate { 8440Sstevel@tonic-gate struct wildcardinfo *wcp; 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate wcp = *wcproot; 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate if (wcp->s == WC_COMPLETE) { 8490Sstevel@tonic-gate ASSERT(wcp->p->refcount == 1); 8500Sstevel@tonic-gate wcp->s = WC_UNDERCONSTRUCTION; 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate /* path has no wildcard */ 8540Sstevel@tonic-gate if (wcp->p->ewname == NULL) 8550Sstevel@tonic-gate return; 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate ASSERT(wcp->oldepname != NULL); 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate tree_free(wcp->nptop->u.event.epname); 8600Sstevel@tonic-gate wcp->nptop->u.event.epname = wcp->oldepname; 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate 863*186Sdb35262 enum wildcard_action { 864*186Sdb35262 WA_NONE, /* do not do any wildcards */ 865*186Sdb35262 WA_SINGLE, /* do wildcard only for current cp node */ 866*186Sdb35262 WA_ALL /* do wildcards for all cp nodes */ 867*186Sdb35262 }; 868*186Sdb35262 8690Sstevel@tonic-gate static void 8700Sstevel@tonic-gate vmatch_event(struct info *infop, struct config *cp, struct node *np, 8710Sstevel@tonic-gate struct node *lnp, struct node *anp, 872*186Sdb35262 struct wildcardinfo **wcproot, enum wildcard_action dowildcard) 8730Sstevel@tonic-gate { 8740Sstevel@tonic-gate struct wildcardinfo *wcp; 8750Sstevel@tonic-gate char *cp_s; 8760Sstevel@tonic-gate int cp_num; 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate wcp = *wcproot; 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate if ((np == NULL && wcp->oldepname != NULL) || 8810Sstevel@tonic-gate (cp == NULL && wcp->oldepname == NULL)) { 8820Sstevel@tonic-gate /* 883*186Sdb35262 * get to this point if the pathname matched the config 884*186Sdb35262 * (but not necessarily a match at the end). first check 885*186Sdb35262 * for any matching wildcard paths. 8860Sstevel@tonic-gate */ 887*186Sdb35262 if (wcp->matchwc != NULL && wc_paths_match(wcp) == 0) 888*186Sdb35262 return; 889*186Sdb35262 8900Sstevel@tonic-gate create_wildcardedpath(wcproot); 8910Sstevel@tonic-gate vmatch(infop, np, lnp, anp, wcproot); 8920Sstevel@tonic-gate undo_wildcardedpath(wcproot); 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate return; 8950Sstevel@tonic-gate } 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate if (cp == NULL) 8980Sstevel@tonic-gate return; /* no more config to match against */ 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate for (; cp; cp = config_next(cp)) { 9010Sstevel@tonic-gate config_getcompname(cp, &cp_s, &cp_num); 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate if (cp_s == np->u.name.s && 9040Sstevel@tonic-gate ! (wcp->s == WC_UNDERCONSTRUCTION && 905*186Sdb35262 dowildcard == WA_SINGLE)) { 9060Sstevel@tonic-gate /* found a matching component name */ 9070Sstevel@tonic-gate if (np->u.name.child && 9080Sstevel@tonic-gate np->u.name.child->t == T_NUM) { 9090Sstevel@tonic-gate /* 9100Sstevel@tonic-gate * an explicit instance number was given 9110Sstevel@tonic-gate * in the source. so only consider this 9120Sstevel@tonic-gate * a configuration match if the number 9130Sstevel@tonic-gate * also matches. 9140Sstevel@tonic-gate */ 9150Sstevel@tonic-gate if (cp_num != np->u.name.child->u.ull) 9160Sstevel@tonic-gate continue; 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate np->u.name.cp = cp; 9190Sstevel@tonic-gate } else { 9200Sstevel@tonic-gate struct iterinfo *iterinfop; 9210Sstevel@tonic-gate const char *iters; 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate /* 9240Sstevel@tonic-gate * vertical iterator. look it up in 9250Sstevel@tonic-gate * the appropriate lut and if we get 9260Sstevel@tonic-gate * back a value it is either one that we 9270Sstevel@tonic-gate * set earlier, in which case we record 9280Sstevel@tonic-gate * the new value for this iteration and 9290Sstevel@tonic-gate * keep matching, or it is one that was 9300Sstevel@tonic-gate * set by an earlier reference to the 9310Sstevel@tonic-gate * iterator, in which case we only consider 9320Sstevel@tonic-gate * this a configuration match if the number 9330Sstevel@tonic-gate * matches cp_num. 9340Sstevel@tonic-gate */ 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate ASSERT(np->u.name.child != NULL); 9370Sstevel@tonic-gate ASSERT(np->u.name.child->t == T_NAME); 9380Sstevel@tonic-gate iters = np->u.name.child->u.name.s; 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate if ((iterinfop = lut_lookup(infop->ex, 9410Sstevel@tonic-gate (void *)iters, NULL)) == NULL) { 9420Sstevel@tonic-gate /* we're the first use, record our np */ 9430Sstevel@tonic-gate infop->ex = lut_add(infop->ex, 9440Sstevel@tonic-gate (void *)iters, 9450Sstevel@tonic-gate newiterinfo(cp_num, np), NULL); 9460Sstevel@tonic-gate } else if (np == iterinfop->np) { 9470Sstevel@tonic-gate /* 9480Sstevel@tonic-gate * we're the first use, back again 9490Sstevel@tonic-gate * for another iteration. so update 9500Sstevel@tonic-gate * the num bound to this iterator in 9510Sstevel@tonic-gate * the lut. 9520Sstevel@tonic-gate */ 9530Sstevel@tonic-gate iterinfop->num = cp_num; 9540Sstevel@tonic-gate } else if (cp_num != iterinfop->num) { 9550Sstevel@tonic-gate /* 9560Sstevel@tonic-gate * an earlier reference to this 9570Sstevel@tonic-gate * iterator bound it to a different 9580Sstevel@tonic-gate * instance number, so there's no 9590Sstevel@tonic-gate * match here after all. 960*186Sdb35262 * 961*186Sdb35262 * however, it's possible that this 962*186Sdb35262 * component should really be part of 963*186Sdb35262 * the wildcard. we explore this by 964*186Sdb35262 * forcing this component into the 965*186Sdb35262 * wildcarded section. 966*186Sdb35262 * 967*186Sdb35262 * for an more details of what's 968*186Sdb35262 * going to happen now, see 969*186Sdb35262 * comments block below entitled 970*186Sdb35262 * "forcing components into 971*186Sdb35262 * wildcard path". 9720Sstevel@tonic-gate */ 973*186Sdb35262 if (dowildcard == WA_ALL && 974*186Sdb35262 wcp->s == WC_UNDERCONSTRUCTION) { 975*186Sdb35262 vmatch_event(infop, cp, np, 976*186Sdb35262 lnp, anp, wcproot, 977*186Sdb35262 WA_SINGLE); 978*186Sdb35262 } 9790Sstevel@tonic-gate continue; 9800Sstevel@tonic-gate } 9810Sstevel@tonic-gate np->u.name.cp = cp; 9820Sstevel@tonic-gate } 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate /* 9850Sstevel@tonic-gate * if wildcarding was done in a call earlier in the 9860Sstevel@tonic-gate * stack, record the current cp as the first 9870Sstevel@tonic-gate * matching and nonwildcarded cp. 9880Sstevel@tonic-gate */ 989*186Sdb35262 if (dowildcard == WA_ALL && 990*186Sdb35262 wcp->s == WC_UNDERCONSTRUCTION) 9910Sstevel@tonic-gate wcp->p->cpstart = cp; 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate /* 9940Sstevel@tonic-gate * if this was an IT_HORIZONTAL name, 9950Sstevel@tonic-gate * hmatch() will use the cp to expand 9960Sstevel@tonic-gate * all matches horizontally into a list. 9970Sstevel@tonic-gate * we know the list will contain at least 9980Sstevel@tonic-gate * one element (the one we just matched), 9990Sstevel@tonic-gate * so we just store cp and let hmatch_event() 10000Sstevel@tonic-gate * do the rest. 10010Sstevel@tonic-gate * 10020Sstevel@tonic-gate * recurse on to next component. note that 10030Sstevel@tonic-gate * wildcarding is now turned off. 10040Sstevel@tonic-gate */ 10050Sstevel@tonic-gate vmatch_event(infop, config_child(cp), np->u.name.next, 1006*186Sdb35262 lnp, anp, wcproot, WA_NONE); 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate /* 1009*186Sdb35262 * forcing components into wildcard path: 1010*186Sdb35262 * 1011*186Sdb35262 * if this component is the first match, force it 1012*186Sdb35262 * to be part of the wildcarded path and see if we 1013*186Sdb35262 * can get additional matches. repeat call to 1014*186Sdb35262 * vmatch_event() with the same np, making sure 1015*186Sdb35262 * wildcarding is forced for this component alone 1016*186Sdb35262 * and not its peers by specifying vmatch_event( 1017*186Sdb35262 * ..., WA_SINGLE). in other words, in the call to 1018*186Sdb35262 * vmatch_event() below, there should be no loop 1019*186Sdb35262 * over cp's peers since that is being done in the 1020*186Sdb35262 * current loop [i.e., the loop we're in now]. 1021*186Sdb35262 * 1022*186Sdb35262 * here's an example. suppose we have the 1023*186Sdb35262 * definition 1024*186Sdb35262 * event foo@x/y 1025*186Sdb35262 * and configuration 1026*186Sdb35262 * a0/x0/y0/a1/x1/y1 1027*186Sdb35262 * 1028*186Sdb35262 * the code up to this point will treat "a0" as the 1029*186Sdb35262 * wildcarded part of the path and "x0/y0" as the 1030*186Sdb35262 * nonwildcarded part, resulting in the instanced 1031*186Sdb35262 * event 1032*186Sdb35262 * foo@a0/x0/y0 1033*186Sdb35262 * 1034*186Sdb35262 * in order to discover the next match (.../x1/y1) 1035*186Sdb35262 * in the configuration we have to force "x0" into 1036*186Sdb35262 * the wildcarded part of the path. the following 1037*186Sdb35262 * call to vmatch_event(..., WA_SINGLE) does this. 1038*186Sdb35262 * by doing so, we discover the wildcarded part 1039*186Sdb35262 * "a0/x0/y0/a1" and the nonwildcarded part "x1/y1" 1040*186Sdb35262 * 1041*186Sdb35262 * the following call to vmatch_event() is also 1042*186Sdb35262 * needed to properly handle the configuration 1043*186Sdb35262 * b0/x0/b1/x1/y1 1044*186Sdb35262 * 1045*186Sdb35262 * the recursions into vmatch_event() will start 1046*186Sdb35262 * off uncovering "b0" as the wildcarded part and 1047*186Sdb35262 * "x0" as the start of the nonwildcarded path. 1048*186Sdb35262 * however, the next recursion will not result in a 1049*186Sdb35262 * match since there is no "y" following "x0". the 1050*186Sdb35262 * subsequent match of (wildcard = "b0/x0/b1" and 1051*186Sdb35262 * nonwildcard = "x1/y1") will be discovered only 1052*186Sdb35262 * if "x0" is forced to be a part of the wildcarded 1053*186Sdb35262 * path. 10540Sstevel@tonic-gate */ 1055*186Sdb35262 if (dowildcard == WA_ALL && 1056*186Sdb35262 wcp->s == WC_UNDERCONSTRUCTION) { 10570Sstevel@tonic-gate vmatch_event(infop, cp, np, lnp, anp, 1058*186Sdb35262 wcproot, WA_SINGLE); 10590Sstevel@tonic-gate } 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate if (np->u.name.it == IT_HORIZONTAL) { 10620Sstevel@tonic-gate /* 10630Sstevel@tonic-gate * hmatch() finished iterating through 10640Sstevel@tonic-gate * the configuration as described above, so 10650Sstevel@tonic-gate * don't continue iterating here. 10660Sstevel@tonic-gate */ 10670Sstevel@tonic-gate return; 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate 1070*186Sdb35262 } else if ((dowildcard == WA_SINGLE || dowildcard == WA_ALL) && 1071*186Sdb35262 wcp->s == WC_UNDERCONSTRUCTION) { 10720Sstevel@tonic-gate /* 10730Sstevel@tonic-gate * no matching cp, and we are constructing our own 10740Sstevel@tonic-gate * wildcard path. (in other words, we are not 10750Sstevel@tonic-gate * referencing a wildcard path created for an 10760Sstevel@tonic-gate * earlier event.) 10770Sstevel@tonic-gate * 10780Sstevel@tonic-gate * add wildcard entry, then recurse on to config 10790Sstevel@tonic-gate * child 10800Sstevel@tonic-gate */ 10810Sstevel@tonic-gate struct node *cpnode, *prevlast; 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate cpnode = tree_name(cp_s, IT_NONE, NULL, 0); 10840Sstevel@tonic-gate cpnode->u.name.child = newnode(T_NUM, NULL, 0); 10850Sstevel@tonic-gate cpnode->u.name.child->u.ull = cp_num; 10860Sstevel@tonic-gate cpnode->u.name.cp = cp; 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate if (wcp->p->ewname == NULL) { 10890Sstevel@tonic-gate prevlast = NULL; 10900Sstevel@tonic-gate wcp->p->ewname = cpnode; 10910Sstevel@tonic-gate } else { 10920Sstevel@tonic-gate prevlast = wcp->p->ewname->u.name.last; 10930Sstevel@tonic-gate wcp->p->ewname = 10940Sstevel@tonic-gate tree_name_append(wcp->p->ewname, 10950Sstevel@tonic-gate cpnode); 10960Sstevel@tonic-gate } 10970Sstevel@tonic-gate 10980Sstevel@tonic-gate vmatch_event(infop, config_child(cp), np, lnp, anp, 1099*186Sdb35262 wcproot, WA_ALL); 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate /* 11020Sstevel@tonic-gate * back out last addition to ewname and continue 11030Sstevel@tonic-gate * with loop 11040Sstevel@tonic-gate */ 11050Sstevel@tonic-gate tree_free(cpnode); 11060Sstevel@tonic-gate if (prevlast == NULL) { 11070Sstevel@tonic-gate wcp->p->ewname = NULL; 11080Sstevel@tonic-gate } else { 11090Sstevel@tonic-gate prevlast->u.name.next = NULL; 11100Sstevel@tonic-gate wcp->p->ewname->u.name.last = prevlast; 11110Sstevel@tonic-gate } 1112*186Sdb35262 1113*186Sdb35262 /* 1114*186Sdb35262 * return if wildcarding is done only for this cp 1115*186Sdb35262 */ 1116*186Sdb35262 if (dowildcard == WA_SINGLE) 1117*186Sdb35262 return; 11180Sstevel@tonic-gate } 11190Sstevel@tonic-gate } 11200Sstevel@tonic-gate } 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate /* 11230Sstevel@tonic-gate * for the event node np, which will be subjected to pathname 11240Sstevel@tonic-gate * expansion/matching, create a (struct wildcardinfo) to hold wildcard 11250Sstevel@tonic-gate * information. this struct will be inserted into the first location in 11260Sstevel@tonic-gate * the list that starts with *wcproot. 11270Sstevel@tonic-gate * 11280Sstevel@tonic-gate * cp is the starting node of the configuration; cpstart, which is output, 11290Sstevel@tonic-gate * is the starting node of the nonwildcarded portion of the path. 11300Sstevel@tonic-gate */ 11310Sstevel@tonic-gate static void 11320Sstevel@tonic-gate add_wildcardentry(struct wildcardinfo **wcproot, struct config *cp, 1133*186Sdb35262 struct node *np) 11340Sstevel@tonic-gate { 11350Sstevel@tonic-gate struct wildcardinfo *wcpnew, *wcp; 11360Sstevel@tonic-gate struct node *np1, *np2; 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate /* 11390Sstevel@tonic-gate * create entry for np 11400Sstevel@tonic-gate */ 11410Sstevel@tonic-gate wcpnew = MALLOC(sizeof (struct wildcardinfo)); 11420Sstevel@tonic-gate bzero(wcpnew, sizeof (struct wildcardinfo)); 11430Sstevel@tonic-gate wcpnew->nptop = np; 11440Sstevel@tonic-gate wcpnew->oldepname = np->u.event.epname; 1145*186Sdb35262 wcpnew->s = WC_UNDERCONSTRUCTION; 1146*186Sdb35262 1147*186Sdb35262 wcpnew->p = MALLOC(sizeof (struct wildcardpath)); 1148*186Sdb35262 bzero(wcpnew->p, sizeof (struct wildcardpath)); 1149*186Sdb35262 wcpnew->p->cpstart = cp; 1150*186Sdb35262 wcpnew->p->refcount = 1; 11510Sstevel@tonic-gate 11520Sstevel@tonic-gate /* 11530Sstevel@tonic-gate * search all completed entries for an epname whose first entry 11540Sstevel@tonic-gate * matches. note that NULL epnames are considered valid and can be 11550Sstevel@tonic-gate * matched. 11560Sstevel@tonic-gate */ 1157*186Sdb35262 np2 = wcpnew->oldepname; 11580Sstevel@tonic-gate for (wcp = *wcproot; wcp; wcp = wcp->next) { 1159*186Sdb35262 ASSERT(wcp->s == WC_COMPLETE); 11600Sstevel@tonic-gate 11610Sstevel@tonic-gate np1 = wcp->oldepname; 11620Sstevel@tonic-gate if ((np1 && np2 && np1->u.name.s == np2->u.name.s) || 11630Sstevel@tonic-gate (np1 == NULL && np2 == NULL)) { 1164*186Sdb35262 /* 1165*186Sdb35262 * if we find a match in a completed entry, set 1166*186Sdb35262 * matchwc to indicate that we would like to match 1167*186Sdb35262 * it. it is necessary to do this since wildcards 1168*186Sdb35262 * for each event are constructed independently. 1169*186Sdb35262 */ 1170*186Sdb35262 wcpnew->matchwc = wcp->p; 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate wcp->p->refcount++; 11730Sstevel@tonic-gate break; 11740Sstevel@tonic-gate } 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate wcpnew->next = *wcproot; 11780Sstevel@tonic-gate *wcproot = wcpnew; 11790Sstevel@tonic-gate } 11800Sstevel@tonic-gate 11810Sstevel@tonic-gate static void 11820Sstevel@tonic-gate delete_wildcardentry(struct wildcardinfo **wcproot) 11830Sstevel@tonic-gate { 11840Sstevel@tonic-gate struct wildcardinfo *wcp; 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate wcp = *wcproot; 11870Sstevel@tonic-gate *wcproot = wcp->next; 11880Sstevel@tonic-gate 11890Sstevel@tonic-gate switch (wcp->s) { 11900Sstevel@tonic-gate case WC_UNDERCONSTRUCTION: 11910Sstevel@tonic-gate case WC_COMPLETE: 1192*186Sdb35262 if (wcp->matchwc != NULL) 1193*186Sdb35262 wcp->matchwc->refcount--; 1194*186Sdb35262 11950Sstevel@tonic-gate ASSERT(wcp->p->refcount == 1); 11960Sstevel@tonic-gate tree_free(wcp->p->ewname); 11970Sstevel@tonic-gate FREE(wcp->p); 11980Sstevel@tonic-gate break; 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate default: 12010Sstevel@tonic-gate out(O_DIE, "deletewc: invalid status"); 12020Sstevel@tonic-gate break; 12030Sstevel@tonic-gate } 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate FREE(wcp); 12060Sstevel@tonic-gate } 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate /* 12090Sstevel@tonic-gate * vmatch -- find the next vertical expansion match in the config database 12100Sstevel@tonic-gate * 12110Sstevel@tonic-gate * this routine is called with three node pointers: 12120Sstevel@tonic-gate * np -- the parse we're matching 12130Sstevel@tonic-gate * lnp -- the rest of the list we're currently working on 12140Sstevel@tonic-gate * anp -- the rest of the arrow we're currently working on 12150Sstevel@tonic-gate * 12160Sstevel@tonic-gate * the expansion matching happens via three types of recursion: 12170Sstevel@tonic-gate * 12180Sstevel@tonic-gate * - when given an arrow, handle the left-side and then recursively 12190Sstevel@tonic-gate * handle the right side (which might be another cascaded arrow). 12200Sstevel@tonic-gate * 12210Sstevel@tonic-gate * - when handling one side of an arrow, recurse through the T_LIST 12220Sstevel@tonic-gate * to get to each event (or just move on to the event if there 12230Sstevel@tonic-gate * is a single event instead of a list) since the arrow parse 12240Sstevel@tonic-gate * trees recurse left, we actually start with the right-most 12250Sstevel@tonic-gate * event list in the prop statement and work our way towards 12260Sstevel@tonic-gate * the left-most event list. 12270Sstevel@tonic-gate * 12280Sstevel@tonic-gate * - when handling an event, recurse down each component of the 12290Sstevel@tonic-gate * pathname, matching in the config database and recording the 12300Sstevel@tonic-gate * matches in the explicit iterator dictionary as we go. 12310Sstevel@tonic-gate * 12320Sstevel@tonic-gate * when the bottom of this matching recursion is met, meaning we have 12330Sstevel@tonic-gate * set the "cp" pointers on all the names in the entire statement, 12340Sstevel@tonic-gate * we call hmatch() which does it's own recursion to handle horizontal 12350Sstevel@tonic-gate * expandsion and then call generate() to generate nodes, bubbles, and 12360Sstevel@tonic-gate * arrows in the instance tree. generate() looks at the cp pointers to 12370Sstevel@tonic-gate * see what instance numbers were matched in the configuration database. 12380Sstevel@tonic-gate * 12390Sstevel@tonic-gate * when horizontal expansion appears, vmatch() finds only the first match 12400Sstevel@tonic-gate * and hmatch() then takes the horizontal expansion through all the other 12410Sstevel@tonic-gate * matches when generating the arrows in the instance tree. 12420Sstevel@tonic-gate * 12430Sstevel@tonic-gate * the "infop" passed down through the recursion contains a dictionary 12440Sstevel@tonic-gate * of the explicit iterators (all the implicit iterators have been converted 12450Sstevel@tonic-gate * to explicit iterators when the parse tree was created by tree.c), which 12460Sstevel@tonic-gate * allows things like this to work correctly: 12470Sstevel@tonic-gate * 12480Sstevel@tonic-gate * prop error.a@x[n]/y/z -> error.b@x/y[n]/z -> error.c@x/y/z[n]; 12490Sstevel@tonic-gate * 12500Sstevel@tonic-gate * during the top level call, the explicit iterator "n" will match an 12510Sstevel@tonic-gate * instance number in the config database, and the result will be recorded 12520Sstevel@tonic-gate * in the explicit iterator dictionary and passed down via "infop". so 12530Sstevel@tonic-gate * when the recursive call tries to match y[n] in the config database, it 12540Sstevel@tonic-gate * will only match the same instance number as x[n] did since the dictionary 12550Sstevel@tonic-gate * is consulted to see if "n" took on a value already. 12560Sstevel@tonic-gate * 12570Sstevel@tonic-gate * at any point during the recursion, match*() can return to indicate 12580Sstevel@tonic-gate * a match was not found in the config database and that the caller should 12590Sstevel@tonic-gate * move on to the next potential match, if any. 12600Sstevel@tonic-gate * 12610Sstevel@tonic-gate * constraints are completely ignored by match(), so the statement: 12620Sstevel@tonic-gate * 12630Sstevel@tonic-gate * prop error.a@x[n] -> error.b@x[n] {n != 0}; 12640Sstevel@tonic-gate * 12650Sstevel@tonic-gate * might very well match x[0] if it appears in the config database. it 12660Sstevel@tonic-gate * is the generate() routine that takes that match and then decides what 12670Sstevel@tonic-gate * arrow, if any, should be generated in the instance tree. generate() 12680Sstevel@tonic-gate * looks at the explicit iterator dictionary to get values like "n" in 12690Sstevel@tonic-gate * the above example so that it can evaluate constraints. 12700Sstevel@tonic-gate * 12710Sstevel@tonic-gate */ 12720Sstevel@tonic-gate static void 12730Sstevel@tonic-gate vmatch(struct info *infop, struct node *np, struct node *lnp, 12740Sstevel@tonic-gate struct node *anp, struct wildcardinfo **wcproot) 12750Sstevel@tonic-gate { 12760Sstevel@tonic-gate if (np == NULL) { 12770Sstevel@tonic-gate if (lnp) 12780Sstevel@tonic-gate vmatch(infop, lnp, NULL, anp, wcproot); 12790Sstevel@tonic-gate else if (anp) 12800Sstevel@tonic-gate vmatch(infop, anp, NULL, NULL, wcproot); 12810Sstevel@tonic-gate else { 12820Sstevel@tonic-gate struct node *src; 12830Sstevel@tonic-gate struct node *dst; 12840Sstevel@tonic-gate 12850Sstevel@tonic-gate /* end of vertical match recursion */ 12860Sstevel@tonic-gate outfl(O_ALTFP|O_VERB3|O_NONL, 12870Sstevel@tonic-gate infop->anp->file, infop->anp->line, "vmatch: "); 12880Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, infop->anp); 12890Sstevel@tonic-gate out(O_ALTFP|O_VERB3, NULL); 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate generate_nork( 12920Sstevel@tonic-gate itree_np2nork(infop->anp->u.arrow.nnp), 12930Sstevel@tonic-gate itree_np2nork(infop->anp->u.arrow.knp)); 12940Sstevel@tonic-gate dst = infop->anp->u.arrow.rhs; 12950Sstevel@tonic-gate src = infop->anp->u.arrow.lhs; 12960Sstevel@tonic-gate for (;;) { 12970Sstevel@tonic-gate generate_new(); /* new set of arrows */ 12980Sstevel@tonic-gate if (src->t == T_ARROW) { 12990Sstevel@tonic-gate hmatch(infop, src->u.arrow.rhs, dst); 13000Sstevel@tonic-gate generate_nork( 13010Sstevel@tonic-gate itree_np2nork(src->u.arrow.nnp), 13020Sstevel@tonic-gate itree_np2nork(src->u.arrow.knp)); 13030Sstevel@tonic-gate dst = src->u.arrow.rhs; 13040Sstevel@tonic-gate src = src->u.arrow.lhs; 13050Sstevel@tonic-gate } else { 13060Sstevel@tonic-gate hmatch(infop, src, dst); 13070Sstevel@tonic-gate break; 13080Sstevel@tonic-gate } 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate } 13110Sstevel@tonic-gate return; 13120Sstevel@tonic-gate } 13130Sstevel@tonic-gate 13140Sstevel@tonic-gate switch (np->t) { 13150Sstevel@tonic-gate case T_EVENT: { 1316*186Sdb35262 add_wildcardentry(wcproot, config_child(infop->croot), np); 1317*186Sdb35262 vmatch_event(infop, config_child(infop->croot), 1318*186Sdb35262 np->u.event.epname, lnp, anp, wcproot, WA_ALL); 13190Sstevel@tonic-gate delete_wildcardentry(wcproot); 13200Sstevel@tonic-gate break; 13210Sstevel@tonic-gate } 13220Sstevel@tonic-gate case T_LIST: 13230Sstevel@tonic-gate ASSERT(lnp == NULL); 13240Sstevel@tonic-gate vmatch(infop, np->u.expr.right, np->u.expr.left, anp, wcproot); 13250Sstevel@tonic-gate break; 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate case T_ARROW: 13280Sstevel@tonic-gate ASSERT(lnp == NULL && anp == NULL); 13290Sstevel@tonic-gate vmatch(infop, np->u.arrow.rhs, NULL, np->u.arrow.lhs, wcproot); 13300Sstevel@tonic-gate break; 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate default: 13330Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 13340Sstevel@tonic-gate "vmatch: unexpected type: %s", 13350Sstevel@tonic-gate ptree_nodetype2str(np->t)); 13360Sstevel@tonic-gate } 13370Sstevel@tonic-gate } 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate static void 13400Sstevel@tonic-gate cp_reset(struct node *np) 13410Sstevel@tonic-gate { 13420Sstevel@tonic-gate if (np == NULL) 13430Sstevel@tonic-gate return; 13440Sstevel@tonic-gate switch (np->t) { 13450Sstevel@tonic-gate case T_NAME: 13460Sstevel@tonic-gate np->u.name.cp = NULL; 13470Sstevel@tonic-gate cp_reset(np->u.name.next); 13480Sstevel@tonic-gate break; 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate case T_LIST: 13510Sstevel@tonic-gate cp_reset(np->u.expr.left); 13520Sstevel@tonic-gate cp_reset(np->u.expr.right); 13530Sstevel@tonic-gate break; 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate case T_ARROW: 13560Sstevel@tonic-gate cp_reset(np->u.arrow.lhs); 13570Sstevel@tonic-gate cp_reset(np->u.arrow.rhs); 13580Sstevel@tonic-gate break; 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate case T_EVENT: 13610Sstevel@tonic-gate cp_reset(np->u.event.epname); 13620Sstevel@tonic-gate break; 13630Sstevel@tonic-gate } 13640Sstevel@tonic-gate } 13650Sstevel@tonic-gate 13660Sstevel@tonic-gate /* 13670Sstevel@tonic-gate * itree_create -- apply the current config to the current parse tree 13680Sstevel@tonic-gate * 13690Sstevel@tonic-gate * returns a lut mapping fully-instance-qualified names to struct events. 13700Sstevel@tonic-gate * 13710Sstevel@tonic-gate */ 13720Sstevel@tonic-gate struct lut * 13730Sstevel@tonic-gate itree_create(struct config *croot) 13740Sstevel@tonic-gate { 13750Sstevel@tonic-gate struct lut *retval; 13760Sstevel@tonic-gate struct node *propnp; 13770Sstevel@tonic-gate 13780Sstevel@tonic-gate Ninfo.lut = NULL; 13790Sstevel@tonic-gate Ninfo.croot = croot; 13800Sstevel@tonic-gate for (propnp = Props; propnp; propnp = propnp->u.stmt.next) { 13810Sstevel@tonic-gate struct node *anp = propnp->u.stmt.np; 13820Sstevel@tonic-gate struct wildcardinfo *wcproot = NULL; 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate ASSERTeq(anp->t, T_ARROW, ptree_nodetype2str); 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate Ninfo.anp = anp; 13870Sstevel@tonic-gate Ninfo.ex = NULL; 13880Sstevel@tonic-gate 13890Sstevel@tonic-gate generate_arrownp(anp); 13900Sstevel@tonic-gate vmatch(&Ninfo, anp, NULL, NULL, &wcproot); 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate if (Ninfo.ex) { 13930Sstevel@tonic-gate lut_free(Ninfo.ex, iterinfo_destructor, NULL); 13940Sstevel@tonic-gate Ninfo.ex = NULL; 13950Sstevel@tonic-gate } 13960Sstevel@tonic-gate ASSERT(wcproot == NULL); 13970Sstevel@tonic-gate cp_reset(anp); 13980Sstevel@tonic-gate } 13990Sstevel@tonic-gate 14000Sstevel@tonic-gate retval = Ninfo.lut; 14010Sstevel@tonic-gate Ninfo.lut = NULL; 14020Sstevel@tonic-gate return (retval); 14030Sstevel@tonic-gate } 14040Sstevel@tonic-gate 14050Sstevel@tonic-gate void 14060Sstevel@tonic-gate itree_free(struct lut *lutp) 14070Sstevel@tonic-gate { 14080Sstevel@tonic-gate lut_free(lutp, itree_destructor, NULL); 14090Sstevel@tonic-gate } 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate int 14120Sstevel@tonic-gate itree_nameinstancecmp(struct node *np1, struct node *np2) 14130Sstevel@tonic-gate { 14140Sstevel@tonic-gate int np1type = (int)np1->u.name.t; 14150Sstevel@tonic-gate int np2type = (int)np2->u.name.t; 14160Sstevel@tonic-gate int num1; 14170Sstevel@tonic-gate int num2; 14180Sstevel@tonic-gate 14190Sstevel@tonic-gate while (np1 && np2 && np1->u.name.s == np2->u.name.s) { 14200Sstevel@tonic-gate if (np1->u.name.next != NULL && np2->u.name.next != NULL) { 14210Sstevel@tonic-gate if (np1->u.name.cp != NULL) { 14220Sstevel@tonic-gate config_getcompname(np1->u.name.cp, NULL, &num1); 14230Sstevel@tonic-gate } else { 14240Sstevel@tonic-gate ASSERT(np1->u.name.child != NULL); 14250Sstevel@tonic-gate ASSERT(np1->u.name.child->t == T_NUM); 14260Sstevel@tonic-gate num1 = (int)np1->u.name.child->u.ull; 14270Sstevel@tonic-gate } 14280Sstevel@tonic-gate 14290Sstevel@tonic-gate if (np2->u.name.cp != NULL) { 14300Sstevel@tonic-gate config_getcompname(np2->u.name.cp, NULL, &num2); 14310Sstevel@tonic-gate } else { 14320Sstevel@tonic-gate ASSERT(np2->u.name.child != NULL); 14330Sstevel@tonic-gate ASSERT(np2->u.name.child->t == T_NUM); 14340Sstevel@tonic-gate num2 = (int)np2->u.name.child->u.ull; 14350Sstevel@tonic-gate } 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate if (num1 != num2) 14380Sstevel@tonic-gate return (num1 - num2); 14390Sstevel@tonic-gate } 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate np1 = np1->u.name.next; 14420Sstevel@tonic-gate np2 = np2->u.name.next; 14430Sstevel@tonic-gate } 14440Sstevel@tonic-gate if (np1 == NULL) 14450Sstevel@tonic-gate if (np2 == NULL) 14460Sstevel@tonic-gate return (np1type - np2type); 14470Sstevel@tonic-gate else 14480Sstevel@tonic-gate return (-1); 14490Sstevel@tonic-gate else if (np2 == NULL) 14500Sstevel@tonic-gate return (1); 14510Sstevel@tonic-gate else 14520Sstevel@tonic-gate return (strcmp(np1->u.name.s, np2->u.name.s)); 14530Sstevel@tonic-gate } 14540Sstevel@tonic-gate 14550Sstevel@tonic-gate void 14560Sstevel@tonic-gate itree_pevent_brief(int flags, struct event *ep) 14570Sstevel@tonic-gate { 14580Sstevel@tonic-gate ASSERT(ep != NULL); 14590Sstevel@tonic-gate ASSERT(ep->enode != NULL); 14600Sstevel@tonic-gate ASSERT(ep->ipp != NULL); 14610Sstevel@tonic-gate 14620Sstevel@tonic-gate ipath_print(flags, ep->enode->u.event.ename->u.name.s, ep->ipp); 14630Sstevel@tonic-gate } 14640Sstevel@tonic-gate 14650Sstevel@tonic-gate /*ARGSUSED*/ 14660Sstevel@tonic-gate static void 14670Sstevel@tonic-gate itree_pevent(struct event *lhs, struct event *ep, void *arg) 14680Sstevel@tonic-gate { 14690Sstevel@tonic-gate struct plut_wlk_data propd; 14700Sstevel@tonic-gate struct bubble *bp; 14710Sstevel@tonic-gate int flags = (int)arg; 14720Sstevel@tonic-gate 14730Sstevel@tonic-gate itree_pevent_brief(flags, ep); 14740Sstevel@tonic-gate if (ep->t == N_EREPORT) 14750Sstevel@tonic-gate out(flags, " (count %d)", ep->count); 14760Sstevel@tonic-gate else 14770Sstevel@tonic-gate out(flags, NULL); 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate if (ep->props) { 14800Sstevel@tonic-gate propd.flags = flags; 14810Sstevel@tonic-gate propd.first = 1; 14820Sstevel@tonic-gate out(flags, "Properties:"); 14830Sstevel@tonic-gate lut_walk(ep->props, ptree_plut, (void *)&propd); 14840Sstevel@tonic-gate } 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp; 14870Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) { 14880Sstevel@tonic-gate /* Print only TO bubbles in this loop */ 14890Sstevel@tonic-gate if (bp->t != B_TO) 14900Sstevel@tonic-gate continue; 14910Sstevel@tonic-gate itree_pbubble(flags, bp); 14920Sstevel@tonic-gate } 14930Sstevel@tonic-gate 14940Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp; 14950Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) { 14960Sstevel@tonic-gate /* Print only INHIBIT bubbles in this loop */ 14970Sstevel@tonic-gate if (bp->t != B_INHIBIT) 14980Sstevel@tonic-gate continue; 14990Sstevel@tonic-gate itree_pbubble(flags, bp); 15000Sstevel@tonic-gate } 15010Sstevel@tonic-gate 15020Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp; 15030Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) { 15040Sstevel@tonic-gate /* Print only FROM bubbles in this loop */ 15050Sstevel@tonic-gate if (bp->t != B_FROM) 15060Sstevel@tonic-gate continue; 15070Sstevel@tonic-gate itree_pbubble(flags, bp); 15080Sstevel@tonic-gate } 15090Sstevel@tonic-gate } 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate static void 15120Sstevel@tonic-gate itree_pbubble(int flags, struct bubble *bp) 15130Sstevel@tonic-gate { 15140Sstevel@tonic-gate struct constraintlist *cp; 15150Sstevel@tonic-gate struct arrowlist *ap; 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate ASSERT(bp != NULL); 15180Sstevel@tonic-gate 15190Sstevel@tonic-gate out(flags|O_NONL, " "); 15200Sstevel@tonic-gate if (bp->mark) 15210Sstevel@tonic-gate out(flags|O_NONL, "*"); 15220Sstevel@tonic-gate else 15230Sstevel@tonic-gate out(flags|O_NONL, " "); 15240Sstevel@tonic-gate if (bp->t == B_FROM) 15250Sstevel@tonic-gate out(flags|O_NONL, "N=%d to:", bp->nork); 15260Sstevel@tonic-gate else if (bp->t == B_TO) 15270Sstevel@tonic-gate out(flags|O_NONL, "K=%d from:", bp->nork); 15280Sstevel@tonic-gate else 15290Sstevel@tonic-gate out(flags|O_NONL, "K=%d masked from:", bp->nork); 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate if (bp->t == B_TO || bp->t == B_INHIBIT) { 15320Sstevel@tonic-gate for (ap = itree_next_arrow(bp, NULL); ap; 15330Sstevel@tonic-gate ap = itree_next_arrow(bp, ap)) { 15340Sstevel@tonic-gate ASSERT(ap->arrowp->head == bp); 15350Sstevel@tonic-gate ASSERT(ap->arrowp->tail != NULL); 15360Sstevel@tonic-gate ASSERT(ap->arrowp->tail->myevent != NULL); 15370Sstevel@tonic-gate out(flags|O_NONL, " "); 15380Sstevel@tonic-gate itree_pevent_brief(flags, ap->arrowp->tail->myevent); 15390Sstevel@tonic-gate } 15400Sstevel@tonic-gate out(flags, NULL); 15410Sstevel@tonic-gate return; 15420Sstevel@tonic-gate } 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate for (ap = itree_next_arrow(bp, NULL); ap; 15450Sstevel@tonic-gate ap = itree_next_arrow(bp, ap)) { 15460Sstevel@tonic-gate ASSERT(ap->arrowp->tail == bp); 15470Sstevel@tonic-gate ASSERT(ap->arrowp->head != NULL); 15480Sstevel@tonic-gate ASSERT(ap->arrowp->head->myevent != NULL); 15490Sstevel@tonic-gate 15500Sstevel@tonic-gate out(flags|O_NONL, " "); 15510Sstevel@tonic-gate itree_pevent_brief(flags, ap->arrowp->head->myevent); 15520Sstevel@tonic-gate 15530Sstevel@tonic-gate out(flags|O_NONL, " "); 15540Sstevel@tonic-gate ptree_timeval(flags, &ap->arrowp->mindelay); 15550Sstevel@tonic-gate out(flags|O_NONL, ","); 15560Sstevel@tonic-gate ptree_timeval(flags, &ap->arrowp->maxdelay); 15570Sstevel@tonic-gate 15580Sstevel@tonic-gate /* Display anything from the propogation node? */ 15590Sstevel@tonic-gate out(O_VERB3|O_NONL, " <%s:%d>", 15600Sstevel@tonic-gate ap->arrowp->pnode->file, ap->arrowp->pnode->line); 15610Sstevel@tonic-gate 15620Sstevel@tonic-gate if (itree_next_constraint(ap->arrowp, NULL)) 15630Sstevel@tonic-gate out(flags|O_NONL, " {"); 15640Sstevel@tonic-gate 15650Sstevel@tonic-gate for (cp = itree_next_constraint(ap->arrowp, NULL); cp; 15660Sstevel@tonic-gate cp = itree_next_constraint(ap->arrowp, cp)) { 15670Sstevel@tonic-gate ptree(flags, cp->cnode, 1, 0); 15680Sstevel@tonic-gate if (itree_next_constraint(ap->arrowp, cp)) 15690Sstevel@tonic-gate out(flags|O_NONL, ", "); 15700Sstevel@tonic-gate } 15710Sstevel@tonic-gate 15720Sstevel@tonic-gate if (itree_next_constraint(ap->arrowp, NULL)) 15730Sstevel@tonic-gate out(flags|O_NONL, "}"); 15740Sstevel@tonic-gate } 15750Sstevel@tonic-gate out(flags, NULL); 15760Sstevel@tonic-gate } 15770Sstevel@tonic-gate 15780Sstevel@tonic-gate void 15790Sstevel@tonic-gate itree_ptree(int flags, struct lut *itp) 15800Sstevel@tonic-gate { 15810Sstevel@tonic-gate lut_walk(itp, (lut_cb)itree_pevent, (void *)flags); 15820Sstevel@tonic-gate } 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate /*ARGSUSED*/ 15850Sstevel@tonic-gate static void 15860Sstevel@tonic-gate itree_destructor(void *left, void *right, void *arg) 15870Sstevel@tonic-gate { 15880Sstevel@tonic-gate struct event *ep = (struct event *)right; 15890Sstevel@tonic-gate struct bubble *nextbub, *bub; 15900Sstevel@tonic-gate 15910Sstevel@tonic-gate /* Free the properties */ 15920Sstevel@tonic-gate lut_free(ep->props, instances_destructor, NULL); 15930Sstevel@tonic-gate 15940Sstevel@tonic-gate /* Free my bubbles */ 15950Sstevel@tonic-gate for (bub = ep->bubbles; bub != NULL; ) { 15960Sstevel@tonic-gate nextbub = bub->next; 15970Sstevel@tonic-gate /* 15980Sstevel@tonic-gate * Free arrows if they are FROM me. Free arrowlists on 15990Sstevel@tonic-gate * other types of bubbles (but not the attached arrows, 16000Sstevel@tonic-gate * which will be freed when we free the originating 16010Sstevel@tonic-gate * bubble. 16020Sstevel@tonic-gate */ 16030Sstevel@tonic-gate if (bub->t == B_FROM) 16040Sstevel@tonic-gate itree_free_arrowlists(bub, 1); 16050Sstevel@tonic-gate else 16060Sstevel@tonic-gate itree_free_arrowlists(bub, 0); 16070Sstevel@tonic-gate itree_free_bubble(bub); 16080Sstevel@tonic-gate bub = nextbub; 16090Sstevel@tonic-gate } 16100Sstevel@tonic-gate 16110Sstevel@tonic-gate if (ep->nvp != NULL) 16120Sstevel@tonic-gate nvlist_free(ep->nvp); 16130Sstevel@tonic-gate bzero(ep, sizeof (*ep)); 16140Sstevel@tonic-gate FREE(ep); 16150Sstevel@tonic-gate } 16160Sstevel@tonic-gate 16170Sstevel@tonic-gate static void 16180Sstevel@tonic-gate itree_free_bubble(struct bubble *freeme) 16190Sstevel@tonic-gate { 16200Sstevel@tonic-gate bzero(freeme, sizeof (*freeme)); 16210Sstevel@tonic-gate FREE(freeme); 16220Sstevel@tonic-gate } 16230Sstevel@tonic-gate 16240Sstevel@tonic-gate static struct bubble * 16250Sstevel@tonic-gate itree_add_bubble(struct event *eventp, enum bubbletype btype, int nork, int gen) 16260Sstevel@tonic-gate { 16270Sstevel@tonic-gate struct bubble *prev = NULL; 16280Sstevel@tonic-gate struct bubble *curr; 16290Sstevel@tonic-gate struct bubble *newb; 16300Sstevel@tonic-gate 16310Sstevel@tonic-gate /* Use existing bubbles as appropriate when possible */ 16320Sstevel@tonic-gate for (curr = eventp->bubbles; 16330Sstevel@tonic-gate curr != NULL; 16340Sstevel@tonic-gate prev = curr, curr = curr->next) { 16350Sstevel@tonic-gate if (btype == B_TO && curr->t == B_TO) { 16360Sstevel@tonic-gate /* see if an existing "to" bubble works for us */ 16370Sstevel@tonic-gate if (gen == curr->gen) 16380Sstevel@tonic-gate return (curr); /* matched gen number */ 16390Sstevel@tonic-gate else if (nork == 1 && curr->nork == 1) { 16400Sstevel@tonic-gate curr->gen = gen; 16410Sstevel@tonic-gate return (curr); /* coalesce K==1 bubbles */ 16420Sstevel@tonic-gate } 16430Sstevel@tonic-gate } else if (btype == B_FROM && curr->t == B_FROM) { 16440Sstevel@tonic-gate /* see if an existing "from" bubble works for us */ 16450Sstevel@tonic-gate if ((nork == N_IS_ALL && curr->nork == N_IS_ALL) || 16460Sstevel@tonic-gate (nork == 0 && curr->nork == 0)) 16470Sstevel@tonic-gate return (curr); 16480Sstevel@tonic-gate } 16490Sstevel@tonic-gate } 16500Sstevel@tonic-gate 16510Sstevel@tonic-gate newb = MALLOC(sizeof (struct bubble)); 16520Sstevel@tonic-gate newb->next = NULL; 16530Sstevel@tonic-gate newb->t = btype; 16540Sstevel@tonic-gate newb->myevent = eventp; 16550Sstevel@tonic-gate newb->nork = nork; 16560Sstevel@tonic-gate newb->mark = 0; 16570Sstevel@tonic-gate newb->gen = gen; 16580Sstevel@tonic-gate newb->arrows = NULL; 16590Sstevel@tonic-gate 16600Sstevel@tonic-gate if (prev == NULL) 16610Sstevel@tonic-gate eventp->bubbles = newb; 16620Sstevel@tonic-gate else 16630Sstevel@tonic-gate prev->next = newb; 16640Sstevel@tonic-gate 16650Sstevel@tonic-gate return (newb); 16660Sstevel@tonic-gate } 16670Sstevel@tonic-gate 16680Sstevel@tonic-gate struct bubble * 16690Sstevel@tonic-gate itree_next_bubble(struct event *eventp, struct bubble *last) 16700Sstevel@tonic-gate { 16710Sstevel@tonic-gate struct bubble *next; 16720Sstevel@tonic-gate 16730Sstevel@tonic-gate for (;;) { 16740Sstevel@tonic-gate if (last != NULL) 16750Sstevel@tonic-gate next = last->next; 16760Sstevel@tonic-gate else 16770Sstevel@tonic-gate next = eventp->bubbles; 16780Sstevel@tonic-gate 16790Sstevel@tonic-gate if (next == NULL || next->arrows != NULL) 16800Sstevel@tonic-gate return (next); 16810Sstevel@tonic-gate 16820Sstevel@tonic-gate /* bubble was empty, skip it */ 16830Sstevel@tonic-gate last = next; 16840Sstevel@tonic-gate } 16850Sstevel@tonic-gate } 16860Sstevel@tonic-gate 16870Sstevel@tonic-gate static void 16880Sstevel@tonic-gate add_arrow(struct bubble *bp, struct arrow *ap) 16890Sstevel@tonic-gate { 16900Sstevel@tonic-gate struct arrowlist *prev = NULL; 16910Sstevel@tonic-gate struct arrowlist *curr; 16920Sstevel@tonic-gate struct arrowlist *newal; 16930Sstevel@tonic-gate 16940Sstevel@tonic-gate newal = MALLOC(sizeof (struct arrowlist)); 16950Sstevel@tonic-gate bzero(newal, sizeof (struct arrowlist)); 16960Sstevel@tonic-gate newal->arrowp = ap; 16970Sstevel@tonic-gate 16980Sstevel@tonic-gate curr = itree_next_arrow(bp, NULL); 16990Sstevel@tonic-gate while (curr != NULL) { 17000Sstevel@tonic-gate prev = curr; 17010Sstevel@tonic-gate curr = itree_next_arrow(bp, curr); 17020Sstevel@tonic-gate } 17030Sstevel@tonic-gate 17040Sstevel@tonic-gate if (prev == NULL) 17050Sstevel@tonic-gate bp->arrows = newal; 17060Sstevel@tonic-gate else 17070Sstevel@tonic-gate prev->next = newal; 17080Sstevel@tonic-gate } 17090Sstevel@tonic-gate 17100Sstevel@tonic-gate static struct arrow * 17110Sstevel@tonic-gate itree_add_arrow(struct bubble *frombubblep, struct bubble *tobubblep, 17120Sstevel@tonic-gate struct node *apnode, struct node *fromevent, struct node *toevent, 17130Sstevel@tonic-gate struct lut *ex) 17140Sstevel@tonic-gate { 17150Sstevel@tonic-gate struct arrow *newa; 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate ASSERTeq(frombubblep->t, B_FROM, itree_bubbletype2str); 17180Sstevel@tonic-gate ASSERTinfo(tobubblep->t == B_TO || tobubblep->t == B_INHIBIT, 17190Sstevel@tonic-gate itree_bubbletype2str(tobubblep->t)); 17200Sstevel@tonic-gate newa = MALLOC(sizeof (struct arrow)); 17210Sstevel@tonic-gate newa->tail = frombubblep; 17220Sstevel@tonic-gate newa->head = tobubblep; 17230Sstevel@tonic-gate newa->pnode = apnode; 17240Sstevel@tonic-gate newa->constraints = NULL; 17250Sstevel@tonic-gate 17260Sstevel@tonic-gate /* 17270Sstevel@tonic-gate * Set default delays, then try to re-set them from 17280Sstevel@tonic-gate * any within() constraints. 17290Sstevel@tonic-gate */ 17300Sstevel@tonic-gate newa->mindelay = newa->maxdelay = 0ULL; 17310Sstevel@tonic-gate if (itree_set_arrow_traits(newa, fromevent, toevent, ex) == 0) { 17320Sstevel@tonic-gate FREE(newa); 17330Sstevel@tonic-gate return (NULL); 17340Sstevel@tonic-gate } 17350Sstevel@tonic-gate 17360Sstevel@tonic-gate add_arrow(frombubblep, newa); 17370Sstevel@tonic-gate add_arrow(tobubblep, newa); 17380Sstevel@tonic-gate return (newa); 17390Sstevel@tonic-gate } 17400Sstevel@tonic-gate 17410Sstevel@tonic-gate /* returns false if traits show that arrow should not be added after all */ 17420Sstevel@tonic-gate static int 17430Sstevel@tonic-gate itree_set_arrow_traits(struct arrow *ap, struct node *fromev, 17440Sstevel@tonic-gate struct node *toev, struct lut *ex) 17450Sstevel@tonic-gate { 17460Sstevel@tonic-gate struct node *epnames[] = { NULL, NULL, NULL }; 17470Sstevel@tonic-gate struct node *newc = NULL; 17480Sstevel@tonic-gate 17490Sstevel@tonic-gate ASSERTeq(fromev->t, T_EVENT, ptree_nodetype2str); 17500Sstevel@tonic-gate ASSERTeq(toev->t, T_EVENT, ptree_nodetype2str); 17510Sstevel@tonic-gate 17520Sstevel@tonic-gate /* 17530Sstevel@tonic-gate * search for the within values first on the declaration of 17540Sstevel@tonic-gate * the destination event, and then on the prop. this allows 17550Sstevel@tonic-gate * one to specify a "default" within by putting it on the 17560Sstevel@tonic-gate * declaration, but then allow overriding on the prop statement. 17570Sstevel@tonic-gate */ 17580Sstevel@tonic-gate arrow_add_within(ap, toev->u.event.declp->u.stmt.np->u.event.eexprlist); 17590Sstevel@tonic-gate arrow_add_within(ap, toev->u.event.eexprlist); 17600Sstevel@tonic-gate 17610Sstevel@tonic-gate /* 17620Sstevel@tonic-gate * handle any global constraints inherited from the 17630Sstevel@tonic-gate * "fromev" event's declaration 17640Sstevel@tonic-gate */ 17650Sstevel@tonic-gate ASSERT(fromev->u.event.declp != NULL); 17660Sstevel@tonic-gate ASSERT(fromev->u.event.declp->u.stmt.np != NULL); 17670Sstevel@tonic-gate 17680Sstevel@tonic-gate #ifdef notdef 17690Sstevel@tonic-gate /* XXX not quite ready to evaluate constraints from decls yet */ 17700Sstevel@tonic-gate if (fromev->u.event.declp->u.stmt.np->u.event.eexprlist) 17710Sstevel@tonic-gate (void) itree_add_constraint(ap, 17720Sstevel@tonic-gate fromev->u.event.declp->u.stmt.np->u.event.eexprlist); 17730Sstevel@tonic-gate #endif /* notdef */ 17740Sstevel@tonic-gate 17750Sstevel@tonic-gate /* handle constraints on the from event in the prop statement */ 17760Sstevel@tonic-gate epnames[0] = fromev->u.event.epname; 17770Sstevel@tonic-gate epnames[1] = toev->u.event.epname; 17780Sstevel@tonic-gate if (eval_potential(fromev->u.event.eexprlist, ex, epnames, &newc) == 0) 17790Sstevel@tonic-gate return (0); /* constraint disallows arrow */ 17800Sstevel@tonic-gate 17810Sstevel@tonic-gate /* 17820Sstevel@tonic-gate * handle any global constraints inherited from the 17830Sstevel@tonic-gate * "toev" event's declaration 17840Sstevel@tonic-gate */ 17850Sstevel@tonic-gate ASSERT(toev->u.event.declp != NULL); 17860Sstevel@tonic-gate ASSERT(toev->u.event.declp->u.stmt.np != NULL); 17870Sstevel@tonic-gate 17880Sstevel@tonic-gate #ifdef notdef 17890Sstevel@tonic-gate /* XXX not quite ready to evaluate constraints from decls yet */ 17900Sstevel@tonic-gate if (toev->u.event.declp->u.stmt.np->u.event.eexprlist) 17910Sstevel@tonic-gate (void) itree_add_constraint(ap, 17920Sstevel@tonic-gate toev->u.event.declp->u.stmt.np->u.event.eexprlist); 17930Sstevel@tonic-gate #endif /* notdef */ 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate /* handle constraints on the to event in the prop statement */ 17960Sstevel@tonic-gate epnames[0] = toev->u.event.epname; 17970Sstevel@tonic-gate epnames[1] = fromev->u.event.epname; 17980Sstevel@tonic-gate if (eval_potential(toev->u.event.eexprlist, ex, epnames, &newc) == 0) 17990Sstevel@tonic-gate return (0); /* constraint disallows arrow */ 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate /* if we came up with any deferred constraints, add them to arrow */ 18020Sstevel@tonic-gate if (newc != NULL) 18030Sstevel@tonic-gate (void) itree_add_constraint(ap, newc); 18040Sstevel@tonic-gate 18050Sstevel@tonic-gate return (1); /* constraints allow arrow */ 18060Sstevel@tonic-gate } 18070Sstevel@tonic-gate 18080Sstevel@tonic-gate /* 18090Sstevel@tonic-gate * Set within() constraint. If the constraint were set multiple times, 18100Sstevel@tonic-gate * the last one would "win". 18110Sstevel@tonic-gate */ 18120Sstevel@tonic-gate static void 18130Sstevel@tonic-gate arrow_add_within(struct arrow *ap, struct node *xpr) 18140Sstevel@tonic-gate { 18150Sstevel@tonic-gate struct node *arglist; 18160Sstevel@tonic-gate 18170Sstevel@tonic-gate /* end of expressions list */ 18180Sstevel@tonic-gate if (xpr == NULL) 18190Sstevel@tonic-gate return; 18200Sstevel@tonic-gate 18210Sstevel@tonic-gate switch (xpr->t) { 18220Sstevel@tonic-gate case T_LIST: 18230Sstevel@tonic-gate arrow_add_within(ap, xpr->u.expr.left); 18240Sstevel@tonic-gate arrow_add_within(ap, xpr->u.expr.right); 18250Sstevel@tonic-gate return; 18260Sstevel@tonic-gate case T_FUNC: 18270Sstevel@tonic-gate if (xpr->u.func.s != L_within) 18280Sstevel@tonic-gate return; 18290Sstevel@tonic-gate arglist = xpr->u.func.arglist; 18300Sstevel@tonic-gate switch (arglist->t) { 18310Sstevel@tonic-gate case T_TIMEVAL: 18320Sstevel@tonic-gate ap->mindelay = 0; 18330Sstevel@tonic-gate ap->maxdelay = arglist->u.ull; 18340Sstevel@tonic-gate break; 18350Sstevel@tonic-gate case T_NAME: 18360Sstevel@tonic-gate ASSERT(arglist->u.name.s == L_infinity); 18370Sstevel@tonic-gate ap->mindelay = 0; 18380Sstevel@tonic-gate ap->maxdelay = TIMEVAL_EVENTUALLY; 18390Sstevel@tonic-gate break; 18400Sstevel@tonic-gate case T_LIST: 18410Sstevel@tonic-gate ASSERT(arglist->u.expr.left->t == T_TIMEVAL); 18420Sstevel@tonic-gate ap->mindelay = arglist->u.expr.left->u.ull; 18430Sstevel@tonic-gate switch (arglist->u.expr.right->t) { 18440Sstevel@tonic-gate case T_TIMEVAL: 18450Sstevel@tonic-gate ap->maxdelay = arglist->u.ull; 18460Sstevel@tonic-gate break; 18470Sstevel@tonic-gate case T_NAME: 18480Sstevel@tonic-gate ASSERT(arglist->u.expr.right->u.name.s == 18490Sstevel@tonic-gate L_infinity); 18500Sstevel@tonic-gate ap->maxdelay = TIMEVAL_EVENTUALLY; 18510Sstevel@tonic-gate break; 18520Sstevel@tonic-gate default: 18530Sstevel@tonic-gate out(O_DIE, "within: unexpected 2nd arg type"); 18540Sstevel@tonic-gate } 18550Sstevel@tonic-gate break; 18560Sstevel@tonic-gate default: 18570Sstevel@tonic-gate out(O_DIE, "within: unexpected 1st arg type"); 18580Sstevel@tonic-gate } 18590Sstevel@tonic-gate break; 18600Sstevel@tonic-gate default: 18610Sstevel@tonic-gate return; 18620Sstevel@tonic-gate } 18630Sstevel@tonic-gate } 18640Sstevel@tonic-gate 18650Sstevel@tonic-gate static void 18660Sstevel@tonic-gate itree_free_arrowlists(struct bubble *bubp, int arrows_too) 18670Sstevel@tonic-gate { 18680Sstevel@tonic-gate struct arrowlist *al, *nal; 18690Sstevel@tonic-gate 18700Sstevel@tonic-gate al = bubp->arrows; 18710Sstevel@tonic-gate while (al != NULL) { 18720Sstevel@tonic-gate nal = al->next; 18730Sstevel@tonic-gate if (arrows_too) { 18740Sstevel@tonic-gate itree_free_constraints(al->arrowp); 18750Sstevel@tonic-gate bzero(al->arrowp, sizeof (struct arrow)); 18760Sstevel@tonic-gate FREE(al->arrowp); 18770Sstevel@tonic-gate } 18780Sstevel@tonic-gate bzero(al, sizeof (*al)); 18790Sstevel@tonic-gate FREE(al); 18800Sstevel@tonic-gate al = nal; 18810Sstevel@tonic-gate } 18820Sstevel@tonic-gate } 18830Sstevel@tonic-gate 18840Sstevel@tonic-gate struct arrowlist * 18850Sstevel@tonic-gate itree_next_arrow(struct bubble *bubble, struct arrowlist *last) 18860Sstevel@tonic-gate { 18870Sstevel@tonic-gate struct arrowlist *next; 18880Sstevel@tonic-gate 18890Sstevel@tonic-gate if (last != NULL) 18900Sstevel@tonic-gate next = last->next; 18910Sstevel@tonic-gate else 18920Sstevel@tonic-gate next = bubble->arrows; 18930Sstevel@tonic-gate return (next); 18940Sstevel@tonic-gate } 18950Sstevel@tonic-gate 18960Sstevel@tonic-gate static struct constraintlist * 18970Sstevel@tonic-gate itree_add_constraint(struct arrow *arrowp, struct node *c) 18980Sstevel@tonic-gate { 18990Sstevel@tonic-gate struct constraintlist *prev = NULL; 19000Sstevel@tonic-gate struct constraintlist *curr; 19010Sstevel@tonic-gate struct constraintlist *newc; 19020Sstevel@tonic-gate 19030Sstevel@tonic-gate for (curr = arrowp->constraints; 19040Sstevel@tonic-gate curr != NULL; 19050Sstevel@tonic-gate prev = curr, curr = curr->next); 19060Sstevel@tonic-gate 19070Sstevel@tonic-gate newc = MALLOC(sizeof (struct constraintlist)); 19080Sstevel@tonic-gate newc->next = NULL; 19090Sstevel@tonic-gate newc->cnode = c; 19100Sstevel@tonic-gate 19110Sstevel@tonic-gate if (prev == NULL) 19120Sstevel@tonic-gate arrowp->constraints = newc; 19130Sstevel@tonic-gate else 19140Sstevel@tonic-gate prev->next = newc; 19150Sstevel@tonic-gate 19160Sstevel@tonic-gate return (newc); 19170Sstevel@tonic-gate } 19180Sstevel@tonic-gate 19190Sstevel@tonic-gate struct constraintlist * 19200Sstevel@tonic-gate itree_next_constraint(struct arrow *arrowp, struct constraintlist *last) 19210Sstevel@tonic-gate { 19220Sstevel@tonic-gate struct constraintlist *next; 19230Sstevel@tonic-gate 19240Sstevel@tonic-gate if (last != NULL) 19250Sstevel@tonic-gate next = last->next; 19260Sstevel@tonic-gate else 19270Sstevel@tonic-gate next = arrowp->constraints; 19280Sstevel@tonic-gate return (next); 19290Sstevel@tonic-gate } 19300Sstevel@tonic-gate 19310Sstevel@tonic-gate static void 19320Sstevel@tonic-gate itree_free_constraints(struct arrow *ap) 19330Sstevel@tonic-gate { 19340Sstevel@tonic-gate struct constraintlist *cl, *ncl; 19350Sstevel@tonic-gate 19360Sstevel@tonic-gate cl = ap->constraints; 19370Sstevel@tonic-gate while (cl != NULL) { 19380Sstevel@tonic-gate ncl = cl->next; 19390Sstevel@tonic-gate ASSERT(cl->cnode != NULL); 19400Sstevel@tonic-gate tree_free(cl->cnode); 19410Sstevel@tonic-gate bzero(cl, sizeof (*cl)); 19420Sstevel@tonic-gate FREE(cl); 19430Sstevel@tonic-gate cl = ncl; 19440Sstevel@tonic-gate } 19450Sstevel@tonic-gate } 19460Sstevel@tonic-gate 19470Sstevel@tonic-gate const char * 19480Sstevel@tonic-gate itree_bubbletype2str(enum bubbletype t) 19490Sstevel@tonic-gate { 19500Sstevel@tonic-gate static char buf[100]; 19510Sstevel@tonic-gate 19520Sstevel@tonic-gate switch (t) { 19530Sstevel@tonic-gate case B_FROM: return L_from; 19540Sstevel@tonic-gate case B_TO: return L_to; 19550Sstevel@tonic-gate case B_INHIBIT: return L_inhibit; 19560Sstevel@tonic-gate default: 19570Sstevel@tonic-gate (void) sprintf(buf, "[unexpected bubbletype: %d]", t); 19580Sstevel@tonic-gate return (buf); 19590Sstevel@tonic-gate } 19600Sstevel@tonic-gate } 19610Sstevel@tonic-gate 19620Sstevel@tonic-gate /* 19630Sstevel@tonic-gate * itree_fini -- clean up any half-built itrees 19640Sstevel@tonic-gate */ 19650Sstevel@tonic-gate void 19660Sstevel@tonic-gate itree_fini(void) 19670Sstevel@tonic-gate { 19680Sstevel@tonic-gate if (Ninfo.lut != NULL) { 19690Sstevel@tonic-gate itree_free(Ninfo.lut); 19700Sstevel@tonic-gate Ninfo.lut = NULL; 19710Sstevel@tonic-gate } 19720Sstevel@tonic-gate if (Ninfo.ex) { 19730Sstevel@tonic-gate lut_free(Ninfo.ex, iterinfo_destructor, NULL); 19740Sstevel@tonic-gate Ninfo.ex = NULL; 19750Sstevel@tonic-gate } 19760Sstevel@tonic-gate } 1977