xref: /onnv-gate/usr/src/cmd/fm/modules/common/eversholt/eval.c (revision 9078:5316b078e4eb)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51717Swesolows  * Common Development and Distribution License (the "License").
61717Swesolows  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211717Swesolows 
220Sstevel@tonic-gate /*
23*9078SStephen.Hanson@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  *
260Sstevel@tonic-gate  * eval.c -- constraint evaluation module
270Sstevel@tonic-gate  *
280Sstevel@tonic-gate  * this module evaluates constraints.
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <ctype.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include "alloc.h"
360Sstevel@tonic-gate #include "out.h"
370Sstevel@tonic-gate #include "stable.h"
380Sstevel@tonic-gate #include "literals.h"
390Sstevel@tonic-gate #include "lut.h"
400Sstevel@tonic-gate #include "tree.h"
410Sstevel@tonic-gate #include "ptree.h"
420Sstevel@tonic-gate #include "itree.h"
431414Scindi #include "ipath.h"
440Sstevel@tonic-gate #include "eval.h"
450Sstevel@tonic-gate #include "config.h"
460Sstevel@tonic-gate #include "platform.h"
471414Scindi #include "fme.h"
481414Scindi #include "stats.h"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate static struct node *eval_dup(struct node *np, struct lut *ex,
514436Sstephh     struct node *events[]);
521414Scindi static int check_expr_args(struct evalue *lp, struct evalue *rp,
531414Scindi     enum datatype dtype, struct node *np);
544436Sstephh static struct node *eval_fru(struct node *np);
554436Sstephh static struct node *eval_asru(struct node *np);
560Sstevel@tonic-gate 
577275Sstephh extern fmd_hdl_t *Hdl;	/* handle from eft.c */
587275Sstephh 
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate  * begins_with -- return true if rhs path begins with everything in lhs path
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate static int
634436Sstephh begins_with(struct node *lhs, struct node *rhs, struct lut *ex)
640Sstevel@tonic-gate {
650Sstevel@tonic-gate 	int lnum;
660Sstevel@tonic-gate 	int rnum;
674436Sstephh 	struct iterinfo *iterinfop;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	if (lhs == NULL)
700Sstevel@tonic-gate 		return (1);	/* yep -- it all matched */
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	if (rhs == NULL)
730Sstevel@tonic-gate 		return (0);	/* nope, ran out of rhs first */
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	ASSERTeq(lhs->t, T_NAME, ptree_nodetype2str);
760Sstevel@tonic-gate 	ASSERTeq(rhs->t, T_NAME, ptree_nodetype2str);
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	if (lhs->u.name.s != rhs->u.name.s)
790Sstevel@tonic-gate 		return (0);	/* nope, different component names */
800Sstevel@tonic-gate 
814436Sstephh 	if (lhs->u.name.child && lhs->u.name.child->t == T_NUM) {
820Sstevel@tonic-gate 		lnum = (int)lhs->u.name.child->u.ull;
834436Sstephh 	} else if (lhs->u.name.child && lhs->u.name.child->t == T_NAME) {
844436Sstephh 		iterinfop = lut_lookup(ex, (void *)lhs->u.name.child->u.name.s,
854436Sstephh 		    NULL);
864436Sstephh 		if (iterinfop != NULL)
874436Sstephh 			lnum = iterinfop->num;
884436Sstephh 		else
894436Sstephh 			out(O_DIE, "begins_with: unexpected lhs child");
904436Sstephh 	} else {
910Sstevel@tonic-gate 		out(O_DIE, "begins_with: unexpected lhs child");
924436Sstephh 	}
930Sstevel@tonic-gate 
944436Sstephh 	if (rhs->u.name.child && rhs->u.name.child->t == T_NUM) {
950Sstevel@tonic-gate 		rnum = (int)rhs->u.name.child->u.ull;
964436Sstephh 	} else if (rhs->u.name.child && rhs->u.name.child->t == T_NAME) {
974436Sstephh 		iterinfop = lut_lookup(ex, (void *)rhs->u.name.child->u.name.s,
984436Sstephh 		    NULL);
994436Sstephh 		if (iterinfop != NULL)
1004436Sstephh 			rnum = iterinfop->num;
1014436Sstephh 		else
1024436Sstephh 			out(O_DIE, "begins_with: unexpected rhs child");
1034436Sstephh 	} else {
1040Sstevel@tonic-gate 		out(O_DIE, "begins_with: unexpected rhs child");
1054436Sstephh 	}
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	if (lnum != rnum)
1080Sstevel@tonic-gate 		return (0);	/* nope, instance numbers were different */
1090Sstevel@tonic-gate 
1104436Sstephh 	return (begins_with(lhs->u.name.next, rhs->u.name.next, ex));
1114436Sstephh }
1124436Sstephh 
1134436Sstephh /*
1144436Sstephh  * eval_getname - used by eval_func to evaluate a name, preferably without using
1154436Sstephh  * eval_dup (but if it does have to use eval_dup then the *dupedp flag is set).
1164436Sstephh  */
1174436Sstephh static struct node *
1184436Sstephh eval_getname(struct node *funcnp, struct lut *ex, struct node *events[],
1194436Sstephh     struct node *np, struct lut **globals,
1204436Sstephh     struct config *croot, struct arrow *arrowp, int try, int *dupedp)
1214436Sstephh {
1224436Sstephh 	struct node *nodep;
1234436Sstephh 	const char *funcname = funcnp->u.func.s;
1244436Sstephh 	struct evalue val;
1254436Sstephh 
1264436Sstephh 	if (np->t == T_NAME)
1274436Sstephh 		nodep = np;
1284436Sstephh 	else if (np->u.func.s == L_fru)
1294436Sstephh 		nodep = eval_fru(np->u.func.arglist);
1304436Sstephh 	else if (np->u.func.s == L_asru)
1314436Sstephh 		nodep = eval_asru(np->u.func.arglist);
1324436Sstephh 	else
1334436Sstephh 		out(O_DIE, "%s: unexpected type: %s",
1344436Sstephh 		    funcname, ptree_nodetype2str(np->t));
1354436Sstephh 	if (try) {
1364436Sstephh 		if (eval_expr(nodep, ex, events, globals, croot,
1374436Sstephh 		    arrowp, try, &val) && val.t == NODEPTR)
1384436Sstephh 			nodep = (struct node *)(uintptr_t)val.v;
1394436Sstephh 		else {
1404436Sstephh 			*dupedp = 1;
1414436Sstephh 			nodep = eval_dup(nodep, ex, events);
1424436Sstephh 		}
1434436Sstephh 	}
1444436Sstephh 	return (nodep);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate /*
1480Sstevel@tonic-gate  * evaluate a variety of functions and place result in valuep.  return 1 if
1490Sstevel@tonic-gate  * function evaluation was successful; 0 if otherwise (e.g., the case of an
1500Sstevel@tonic-gate  * invalid argument to the function)
1510Sstevel@tonic-gate  */
1520Sstevel@tonic-gate /*ARGSUSED*/
1530Sstevel@tonic-gate static int
1544436Sstephh eval_func(struct node *funcnp, struct lut *ex, struct node *events[],
1550Sstevel@tonic-gate     struct node *np, struct lut **globals,
1560Sstevel@tonic-gate     struct config *croot, struct arrow *arrowp, int try, struct evalue *valuep)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate 	const char *funcname = funcnp->u.func.s;
1594436Sstephh 	int duped_lhs = 0, duped_rhs = 0, duped = 0;
1604436Sstephh 	struct node *lhs;
1614436Sstephh 	struct node *rhs;
1624436Sstephh 	struct config *cp;
1634436Sstephh 	struct node *nodep;
1644436Sstephh 	char *path;
1654436Sstephh 	struct evalue val;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	if (funcname == L_within) {
1680Sstevel@tonic-gate 		/* within()'s are not really constraints -- always true */
1690Sstevel@tonic-gate 		valuep->t = UINT64;
1700Sstevel@tonic-gate 		valuep->v = 1;
1710Sstevel@tonic-gate 		return (1);
1720Sstevel@tonic-gate 	} else if (funcname == L_is_under) {
1734436Sstephh 		lhs = eval_getname(funcnp, ex, events, np->u.expr.left, globals,
1744436Sstephh 		    croot, arrowp, try, &duped_lhs);
1754436Sstephh 		rhs = eval_getname(funcnp, ex, events, np->u.expr.right,
1764436Sstephh 		    globals, croot, arrowp, try, &duped_rhs);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 		valuep->t = UINT64;
1794436Sstephh 		valuep->v = begins_with(lhs, rhs, ex);
1800Sstevel@tonic-gate 		out(O_ALTFP|O_VERB2|O_NONL, "eval_func:is_under(");
1810Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, lhs);
1820Sstevel@tonic-gate 		out(O_ALTFP|O_VERB2|O_NONL, ",");
1830Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, rhs);
1844436Sstephh 		out(O_ALTFP|O_VERB2|O_NONL, ") returned %d", (int)valuep->v);
1850Sstevel@tonic-gate 
1864436Sstephh 		if (duped_lhs)
1874436Sstephh 			tree_free(lhs);
1884436Sstephh 		if (duped_rhs)
1894436Sstephh 			tree_free(rhs);
1900Sstevel@tonic-gate 		return (1);
1912869Sgavinm 	} else if (funcname == L_confprop || funcname == L_confprop_defined) {
1922318Sstephh 		const char *s;
1932318Sstephh 
1942318Sstephh 		/* for now s will point to a quote [see addconfigprop()] */
1952318Sstephh 		ASSERT(np->u.expr.right->t == T_QUOTE);
1962318Sstephh 
1974436Sstephh 		nodep = eval_getname(funcnp, ex, events, np->u.expr.left,
1984436Sstephh 		    globals, croot, arrowp, try, &duped);
1994436Sstephh 		if (nodep->u.name.last->u.name.cp != NULL) {
2004436Sstephh 			cp = nodep->u.name.last->u.name.cp;
2014436Sstephh 		} else {
2024436Sstephh 			path = ipath2str(NULL, ipath(nodep));
2034436Sstephh 			cp = config_lookup(croot, path, 0);
2044436Sstephh 			FREE((void *)path);
2054436Sstephh 		}
2062869Sgavinm 		if (cp == NULL) {
2074436Sstephh 			if (funcname == L_confprop) {
2084436Sstephh 				out(O_ALTFP|O_VERB3, "%s: path ", funcname);
2094436Sstephh 				ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep);
2104436Sstephh 				out(O_ALTFP|O_VERB3, " not found");
2114436Sstephh 				valuep->v = (uintptr_t)stable("");
2124436Sstephh 				valuep->t = STRING;
2134436Sstephh 				if (duped)
2144436Sstephh 					tree_free(nodep);
2154436Sstephh 				return (1);
2164436Sstephh 			} else {
2172869Sgavinm 				valuep->v = 0;
2182869Sgavinm 				valuep->t = UINT64;
2194436Sstephh 				if (duped)
2204436Sstephh 					tree_free(nodep);
2212869Sgavinm 				return (1);
2222869Sgavinm 			}
2232869Sgavinm 		}
2242318Sstephh 		s = config_getprop(cp, np->u.expr.right->u.quote.s);
2254436Sstephh 		if (s == NULL && strcmp(np->u.expr.right->u.quote.s,
2264436Sstephh 		    "class-code") == 0)
2274436Sstephh 			s = config_getprop(cp, "CLASS-CODE");
2282869Sgavinm 		if (s == NULL) {
2294436Sstephh 			if (funcname == L_confprop) {
2304436Sstephh 				out(O_ALTFP|O_VERB3|O_NONL,
2314436Sstephh 				    "%s: \"%s\" not found for path ",
2324436Sstephh 				    funcname, np->u.expr.right->u.quote.s);
2334436Sstephh 				ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep);
2344436Sstephh 				valuep->v = (uintptr_t)stable("");
2354436Sstephh 				valuep->t = STRING;
2364436Sstephh 				if (duped)
2374436Sstephh 					tree_free(nodep);
2384436Sstephh 				return (1);
2394436Sstephh 			} else {
2402869Sgavinm 				valuep->v = 0;
2412869Sgavinm 				valuep->t = UINT64;
2424436Sstephh 				if (duped)
2434436Sstephh 					tree_free(nodep);
2442869Sgavinm 				return (1);
2452869Sgavinm 			}
2462869Sgavinm 		}
2472869Sgavinm 
2482869Sgavinm 		if (funcname == L_confprop) {
2492869Sgavinm 			valuep->v = (uintptr_t)stable(s);
2502869Sgavinm 			valuep->t = STRING;
2514436Sstephh 			out(O_ALTFP|O_VERB3|O_NONL, "  %s(\"", funcname);
2524436Sstephh 			ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep);
2534436Sstephh 			out(O_ALTFP|O_VERB3|O_NONL,
2544436Sstephh 			    "\", \"%s\") = \"%s\"  ",
2554436Sstephh 			    np->u.expr.right->u.quote.s,
2562869Sgavinm 			    (char *)(uintptr_t)valuep->v);
2572869Sgavinm 		} else {
2582869Sgavinm 			valuep->v = 1;
2592869Sgavinm 			valuep->t = UINT64;
2602869Sgavinm 		}
2614436Sstephh 		if (duped)
2624436Sstephh 			tree_free(nodep);
2634436Sstephh 		return (1);
2644436Sstephh 	} else if (funcname == L_is_connected) {
2654436Sstephh 		const char *connstrings[] = { "connected", "CONNECTED", NULL };
2664436Sstephh 		struct config *cp[2];
2674436Sstephh 		const char *matchthis[2], *s;
2684436Sstephh 		char *nameslist, *w;
2694436Sstephh 		int i, j;
2704436Sstephh 
2714436Sstephh 		lhs = eval_getname(funcnp, ex, events, np->u.expr.left, globals,
2724436Sstephh 		    croot, arrowp, try, &duped_lhs);
2734436Sstephh 		rhs = eval_getname(funcnp, ex, events, np->u.expr.right,
2744436Sstephh 		    globals, croot, arrowp, try, &duped_rhs);
2754436Sstephh 		path = ipath2str(NULL, ipath(lhs));
2764436Sstephh 		matchthis[1] = stable(path);
2774436Sstephh 		if (lhs->u.name.last->u.name.cp != NULL)
2784436Sstephh 			cp[0] = lhs->u.name.last->u.name.cp;
2794436Sstephh 		else
2804436Sstephh 			cp[0] = config_lookup(croot, path, 0);
2812869Sgavinm 		FREE((void *)path);
2824436Sstephh 		path = ipath2str(NULL, ipath(rhs));
2834436Sstephh 		matchthis[0] = stable(path);
2844436Sstephh 		if (rhs->u.name.last->u.name.cp != NULL)
2854436Sstephh 			cp[1] = rhs->u.name.last->u.name.cp;
2864436Sstephh 		else
2874436Sstephh 			cp[1] = config_lookup(croot, path, 0);
2884436Sstephh 		FREE((void *)path);
2894436Sstephh 		if (duped_lhs)
2904436Sstephh 			tree_free(lhs);
2914436Sstephh 		if (duped_rhs)
2924436Sstephh 			tree_free(rhs);
2934436Sstephh 
2944436Sstephh 		valuep->t = UINT64;
2954436Sstephh 		valuep->v = 0;
2964436Sstephh 		if (cp[0] == NULL || cp[1] == NULL)
2974436Sstephh 			return (1);
2984436Sstephh 
2994436Sstephh 		/* to thine self always be connected */
3004436Sstephh 		if (cp[0] == cp[1]) {
3014436Sstephh 			valuep->v = 1;
3024436Sstephh 			return (1);
3034436Sstephh 		}
3044436Sstephh 
3054436Sstephh 		/*
3064436Sstephh 		 * Extract "connected" property from each cp. Search this
3074436Sstephh 		 * property for the name associated with the other cp[].
3084436Sstephh 		 */
3094436Sstephh 		for (i = 0; i < 2 && valuep->v == 0; i++) {
3104436Sstephh 			for (j = 0; connstrings[j] != NULL && valuep->v == 0;
3114436Sstephh 			    j++) {
3124436Sstephh 				s = config_getprop(cp[i],
3134436Sstephh 				    stable(connstrings[j]));
3144436Sstephh 				if (s != NULL) {
3154436Sstephh 					nameslist = STRDUP(s);
3164436Sstephh 					w = strtok(nameslist, " ,");
3174436Sstephh 					while (w != NULL) {
3184436Sstephh 						if (stable(w) == matchthis[i]) {
3194436Sstephh 							valuep->v = 1;
3204436Sstephh 							break;
3214436Sstephh 						}
3224436Sstephh 						w = strtok(NULL, " ,");
3234436Sstephh 					}
3244436Sstephh 					FREE(nameslist);
3254436Sstephh 				}
3264436Sstephh 			}
3274436Sstephh 		}
3282318Sstephh 		return (1);
3294436Sstephh 	} else if (funcname == L_is_type) {
3304436Sstephh 		const char *typestrings[] = { "type", "TYPE", NULL };
3314436Sstephh 		const char *s;
3324436Sstephh 		int i;
3334436Sstephh 
3344436Sstephh 		nodep = eval_getname(funcnp, ex, events, np, globals,
3354436Sstephh 		    croot, arrowp, try, &duped);
3364436Sstephh 		if (nodep->u.name.last->u.name.cp != NULL) {
3374436Sstephh 			cp = nodep->u.name.last->u.name.cp;
3384436Sstephh 		} else {
3394436Sstephh 			path = ipath2str(NULL, ipath(nodep));
3404436Sstephh 			cp = config_lookup(croot, path, 0);
3414436Sstephh 			FREE((void *)path);
3424436Sstephh 		}
3434436Sstephh 		if (duped)
3444436Sstephh 			tree_free(nodep);
3454436Sstephh 
3464436Sstephh 		valuep->t = STRING;
3474436Sstephh 		valuep->v = (uintptr_t)stable("");
3484436Sstephh 		if (cp == NULL)
3494436Sstephh 			return (1);
3504436Sstephh 		for (i = 0; typestrings[i] != NULL; i++) {
3514436Sstephh 			s = config_getprop(cp, stable(typestrings[i]));
3524436Sstephh 			if (s != NULL) {
3534436Sstephh 				valuep->v = (uintptr_t)stable(s);
3544436Sstephh 				break;
3554436Sstephh 			}
3564436Sstephh 		}
3574436Sstephh 		return (1);
3584436Sstephh 	} else if (funcname == L_is_on) {
3594436Sstephh 		const char *onstrings[] = { "on", "ON", NULL };
3604436Sstephh 		const char *truestrings[] = { "yes", "YES", "y", "Y",
3614436Sstephh 				    "true", "TRUE", "t", "T", "1", NULL };
3624436Sstephh 		const char *s;
3634436Sstephh 		int i, j;
3644436Sstephh 
3654436Sstephh 		nodep = eval_getname(funcnp, ex, events, np, globals,
3664436Sstephh 		    croot, arrowp, try, &duped);
3674436Sstephh 		if (nodep->u.name.last->u.name.cp != NULL) {
3684436Sstephh 			cp = nodep->u.name.last->u.name.cp;
3694436Sstephh 		} else {
3704436Sstephh 			path = ipath2str(NULL, ipath(nodep));
3714436Sstephh 			cp = config_lookup(croot, path, 0);
3724436Sstephh 			FREE((void *)path);
3734436Sstephh 		}
3744436Sstephh 		if (duped)
3754436Sstephh 			tree_free(nodep);
3764436Sstephh 
3774436Sstephh 		valuep->t = UINT64;
3784436Sstephh 		valuep->v = 0;
3794436Sstephh 		if (cp == NULL)
3804436Sstephh 			return (1);
3814436Sstephh 		for (i = 0; onstrings[i] != NULL; i++) {
3824436Sstephh 			s = config_getprop(cp, stable(onstrings[i]));
3834436Sstephh 			if (s != NULL) {
3844436Sstephh 				s = stable(s);
3854436Sstephh 				for (j = 0; truestrings[j] != NULL; j++) {
3864436Sstephh 					if (s == stable(truestrings[j])) {
3874436Sstephh 						valuep->v = 1;
3884436Sstephh 						return (1);
3894436Sstephh 					}
3904436Sstephh 				}
3914436Sstephh 			}
3924436Sstephh 		}
3934436Sstephh 		return (1);
3944436Sstephh 	} else if (funcname == L_is_present) {
3954436Sstephh 		nodep = eval_getname(funcnp, ex, events, np, globals,
3964436Sstephh 		    croot, arrowp, try, &duped);
3974436Sstephh 		if (nodep->u.name.last->u.name.cp != NULL) {
3984436Sstephh 			cp = nodep->u.name.last->u.name.cp;
3994436Sstephh 		} else {
4004436Sstephh 			path = ipath2str(NULL, ipath(nodep));
4014436Sstephh 			cp = config_lookup(croot, path, 0);
4024436Sstephh 			FREE((void *)path);
4034436Sstephh 		}
4044436Sstephh 		if (duped)
4054436Sstephh 			tree_free(nodep);
4064436Sstephh 
4074436Sstephh 		valuep->t = UINT64;
4084436Sstephh 		valuep->v = 0;
4094436Sstephh 		if (cp != NULL)
4104436Sstephh 			valuep->v = 1;
4114436Sstephh 		return (1);
4127275Sstephh 	} else if (funcname == L_has_fault) {
4137275Sstephh 		nvlist_t *asru = NULL, *fru = NULL, *rsrc = NULL;
4147275Sstephh 
4157275Sstephh 		nodep = eval_getname(funcnp, ex, events, np->u.expr.left,
4167275Sstephh 		    globals, croot, arrowp, try, &duped);
4177275Sstephh 		path = ipath2str(NULL, ipath(nodep));
4187275Sstephh 		platform_units_translate(0, croot, &asru, &fru, &rsrc, path);
4198245SStephen.Hanson@Sun.COM 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, "has_fault(");
4208245SStephen.Hanson@Sun.COM 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.left);
4218245SStephen.Hanson@Sun.COM 		out(O_ALTFP|O_VERB2|O_NONL, ", \"%s\") ",
4228245SStephen.Hanson@Sun.COM 		    np->u.expr.right->u.quote.s);
4237275Sstephh 		FREE((void *)path);
4247275Sstephh 		if (duped)
4257275Sstephh 			tree_free(nodep);
4267275Sstephh 
4278245SStephen.Hanson@Sun.COM 		if (rsrc == NULL) {
4287275Sstephh 			valuep->v = 0;
4298245SStephen.Hanson@Sun.COM 			out(O_ALTFP|O_VERB2, "no path");
4308245SStephen.Hanson@Sun.COM 		} else {
4317275Sstephh 			valuep->v = fmd_nvl_fmri_has_fault(Hdl, rsrc,
4327275Sstephh 			    FMD_HAS_FAULT_RESOURCE,
4337275Sstephh 			    strcmp(np->u.expr.right->u.quote.s, "") == 0 ?
4347275Sstephh 			    NULL : (char *)np->u.expr.right->u.quote.s);
4358245SStephen.Hanson@Sun.COM 			out(O_ALTFP|O_VERB2, "returned %lld", valuep->v);
4368245SStephen.Hanson@Sun.COM 		}
4377275Sstephh 		valuep->t = UINT64;
4387275Sstephh 		return (1);
4394436Sstephh 	} else if (funcname == L_count) {
4404436Sstephh 		struct stats *statp;
4414436Sstephh 		struct istat_entry ent;
4424436Sstephh 
4434436Sstephh 		ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t));
4444436Sstephh 
4454436Sstephh 		nodep = np->u.event.epname;
4464436Sstephh 		if (try) {
4474436Sstephh 			if (eval_expr(nodep, ex, events, globals,
4484436Sstephh 			    croot, arrowp, try, &val) && val.t == NODEPTR)
4494436Sstephh 				nodep = (struct node *)(uintptr_t)val.v;
4504436Sstephh 			else {
4514436Sstephh 				duped = 1;
4524436Sstephh 				nodep = eval_dup(nodep, ex, events);
4534436Sstephh 			}
4544436Sstephh 		}
4554436Sstephh 		ent.ename = np->u.event.ename->u.name.s;
4564436Sstephh 		ent.ipath = ipath(nodep);
4574436Sstephh 		valuep->t = UINT64;
4584436Sstephh 		if ((statp = (struct stats *)
4594436Sstephh 		    lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL)
4604436Sstephh 			valuep->v = 0;
4614436Sstephh 		else
4624436Sstephh 			valuep->v = stats_counter_value(statp);
4634436Sstephh 		if (duped)
4644436Sstephh 			tree_free(nodep);
4654436Sstephh 		return (1);
4664436Sstephh 	} else if (funcname == L_envprop) {
4674436Sstephh 		outfl(O_DIE, np->file, np->line,
4684436Sstephh 		    "eval_func: %s not yet supported", funcname);
4690Sstevel@tonic-gate 	}
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	if (try)
4720Sstevel@tonic-gate 		return (0);
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	if (funcname == L_fru) {
4750Sstevel@tonic-gate 		valuep->t = NODEPTR;
4761717Swesolows 		valuep->v = (uintptr_t)eval_fru(np);
4770Sstevel@tonic-gate 		return (1);
4780Sstevel@tonic-gate 	} else if (funcname == L_asru) {
4790Sstevel@tonic-gate 		valuep->t = NODEPTR;
4801717Swesolows 		valuep->v = (uintptr_t)eval_asru(np);
4810Sstevel@tonic-gate 		return (1);
4821414Scindi 	} else if (funcname == L_defined) {
4831414Scindi 		ASSERTeq(np->t, T_GLOBID, ptree_nodetype2str);
4841414Scindi 		valuep->t = UINT64;
4851414Scindi 		valuep->v = (lut_lookup(*globals,
4861414Scindi 		    (void *)np->u.globid.s, NULL) != NULL);
4871414Scindi 		return (1);
4880Sstevel@tonic-gate 	} else if (funcname == L_call) {
4890Sstevel@tonic-gate 		return (! platform_call(np, globals, croot, arrowp, valuep));
4900Sstevel@tonic-gate 	} else if (funcname == L_payloadprop) {
4911414Scindi 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
4920Sstevel@tonic-gate 		    "payloadprop(\"%s\") ", np->u.quote.s);
493186Sdb35262 
4945204Sstephh 		if (arrowp->head->myevent->count == 0) {
4955204Sstephh 			/*
4965204Sstephh 			 * Haven't seen this ereport yet, so must defer
4975204Sstephh 			 */
4985204Sstephh 			out(O_ALTFP|O_VERB2, "ereport not yet seen - defer.");
4995204Sstephh 			return (0);
5005204Sstephh 		} else if (platform_payloadprop(np, valuep)) {
5011414Scindi 			/* platform_payloadprop() returned false */
5025204Sstephh 			out(O_ALTFP|O_VERB, "not found.");
5035204Sstephh 			valuep->t = UNDEFINED;
5045204Sstephh 			return (1);
5051414Scindi 		} else {
506186Sdb35262 			switch (valuep->t) {
507186Sdb35262 			case UINT64:
508186Sdb35262 			case NODEPTR:
5091414Scindi 				out(O_ALTFP|O_VERB2, "found: %llu", valuep->v);
510186Sdb35262 				break;
511186Sdb35262 			case STRING:
5121414Scindi 				out(O_ALTFP|O_VERB2, "found: \"%s\"",
5131717Swesolows 				    (char *)(uintptr_t)valuep->v);
514186Sdb35262 				break;
515186Sdb35262 			default:
5161414Scindi 				out(O_ALTFP|O_VERB2, "found: undefined");
517186Sdb35262 				break;
518186Sdb35262 			}
5191414Scindi 			return (1);
5201414Scindi 		}
5211414Scindi 	} else if (funcname == L_setpayloadprop) {
5221414Scindi 		struct evalue *payloadvalp;
5235204Sstephh 		int alloced = 0;
5241414Scindi 
5251414Scindi 		ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t));
5261414Scindi 		ASSERTinfo(np->u.expr.left->t == T_QUOTE,
5271414Scindi 		    ptree_nodetype2str(np->u.expr.left->t));
5281414Scindi 
529*9078SStephen.Hanson@Sun.COM 		if (!(arrowp->head->myevent->cached_state & REQMNTS_CREDIBLE))
5307197Sstephh 			return (0);
5317197Sstephh 
5321414Scindi 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
5331414Scindi 		    "setpayloadprop: %s: %s=",
5341414Scindi 		    arrowp->tail->myevent->enode->u.event.ename->u.name.s,
5351414Scindi 		    np->u.expr.left->u.quote.s);
5361414Scindi 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right);
5371414Scindi 
5381414Scindi 		/*
5391414Scindi 		 * allocate a struct evalue to hold the payload property's
5401414Scindi 		 * value, unless we've been here already, in which case we
5411414Scindi 		 * might calculate a different value, but we'll store it
5421414Scindi 		 * in the already-allocated struct evalue.
5431414Scindi 		 */
5441414Scindi 		if ((payloadvalp = (struct evalue *)lut_lookup(
5451414Scindi 		    arrowp->tail->myevent->payloadprops,
5461414Scindi 		    (void *)np->u.expr.left->u.quote.s, NULL)) == NULL) {
5471414Scindi 			payloadvalp = MALLOC(sizeof (*payloadvalp));
5485204Sstephh 			alloced = 1;
5491414Scindi 		}
5501414Scindi 
5514436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
5521414Scindi 		    arrowp, try, payloadvalp)) {
5535204Sstephh 			out(O_ALTFP|O_VERB2, " (cannot eval)");
5545204Sstephh 			if (alloced)
5555204Sstephh 				FREE(payloadvalp);
5565204Sstephh 			return (0);
5571414Scindi 		} else {
5585204Sstephh 			if (payloadvalp->t == UNDEFINED) {
5595204Sstephh 				/* function is always true */
5605204Sstephh 				out(O_ALTFP|O_VERB2, " (undefined)");
5615204Sstephh 				valuep->t = UINT64;
5625204Sstephh 				valuep->v = 1;
5635204Sstephh 				return (1);
5645204Sstephh 			}
5651414Scindi 			if (payloadvalp->t == UINT64)
5661414Scindi 				out(O_ALTFP|O_VERB2,
5671414Scindi 				    " (%llu)", payloadvalp->v);
5681414Scindi 			else
5691717Swesolows 				out(O_ALTFP|O_VERB2, " (\"%s\")",
5701717Swesolows 				    (char *)(uintptr_t)payloadvalp->v);
5711414Scindi 		}
5721414Scindi 
5731414Scindi 		/* add to table of payload properties for current problem */
5741414Scindi 		arrowp->tail->myevent->payloadprops =
5751414Scindi 		    lut_add(arrowp->tail->myevent->payloadprops,
5761414Scindi 		    (void *)np->u.expr.left->u.quote.s,
5771414Scindi 		    (void *)payloadvalp, NULL);
5781414Scindi 
5791414Scindi 		/* function is always true */
5801414Scindi 		valuep->t = UINT64;
5811414Scindi 		valuep->v = 1;
5821414Scindi 		return (1);
5837197Sstephh 	} else if (funcname == L_setserdn || funcname == L_setserdt ||
5847197Sstephh 	    funcname == L_setserdsuffix || funcname == L_setserdincrement) {
5857197Sstephh 		struct evalue *serdvalp;
5867197Sstephh 		int alloced = 0;
5877197Sstephh 		char *str;
5887197Sstephh 		struct event *flt = arrowp->tail->myevent;
5897197Sstephh 
590*9078SStephen.Hanson@Sun.COM 		if (!(arrowp->head->myevent->cached_state & REQMNTS_CREDIBLE))
5917197Sstephh 			return (0);
5927197Sstephh 
5937197Sstephh 		if (funcname == L_setserdn)
5947197Sstephh 			str = "n";
5957197Sstephh 		else if (funcname == L_setserdt)
5967197Sstephh 			str = "t";
5977197Sstephh 		else if (funcname == L_setserdsuffix)
5987197Sstephh 			str = "suffix";
5997197Sstephh 		else if (funcname == L_setserdincrement)
6007197Sstephh 			str = "increment";
6017197Sstephh 
6027197Sstephh 		/*
6037197Sstephh 		 * allocate a struct evalue to hold the serd property's
6047197Sstephh 		 * value, unless we've been here already, in which case we
6057197Sstephh 		 * might calculate a different value, but we'll store it
6067197Sstephh 		 * in the already-allocated struct evalue.
6077197Sstephh 		 */
6087197Sstephh 		if ((serdvalp = (struct evalue *)lut_lookup(flt->serdprops,
6097392SScott.Davenport@Sun.COM 		    (void *)str, (lut_cmp)strcmp)) == NULL) {
6107197Sstephh 			serdvalp = MALLOC(sizeof (*serdvalp));
6117197Sstephh 			alloced = 1;
6127197Sstephh 		}
6137197Sstephh 
6147197Sstephh 		if (!eval_expr(np, ex, events, globals, croot, arrowp, try,
6157197Sstephh 		    serdvalp)) {
6167197Sstephh 			outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
6177197Sstephh 			    "setserd%s: %s: ", str,
6187197Sstephh 			    flt->enode->u.event.ename->u.name.s);
6197197Sstephh 			ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np);
6207197Sstephh 			out(O_ALTFP|O_VERB2, " (cannot eval)");
6217197Sstephh 			if (alloced)
6227197Sstephh 				FREE(serdvalp);
6237197Sstephh 			return (0);
6247197Sstephh 		} else if (serdvalp->t == UNDEFINED) {
6257197Sstephh 			outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
6267197Sstephh 			    "setserd%s: %s: ", str,
6277197Sstephh 			    flt->enode->u.event.ename->u.name.s);
6287197Sstephh 			ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np);
6297197Sstephh 			out(O_ALTFP|O_VERB2, " (undefined)");
6307197Sstephh 		} else {
6317197Sstephh 			outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
6327197Sstephh 			    "setserd%s: %s: ", str,
6337197Sstephh 			    flt->enode->u.event.ename->u.name.s);
6347197Sstephh 			ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np);
6357197Sstephh 			if ((funcname == L_setserdincrement ||
6367197Sstephh 			    funcname == L_setserdn) && serdvalp->t == STRING) {
6377197Sstephh 				serdvalp->t = UINT64;
6387197Sstephh 				serdvalp->v = strtoull((char *)
6397197Sstephh 				    (uintptr_t)serdvalp->v, NULL, 0);
6407197Sstephh 			}
6417197Sstephh 			if (funcname == L_setserdt && serdvalp->t == UINT64) {
6427197Sstephh 				int len = snprintf(NULL, 0, "%lldns",
6437197Sstephh 				    serdvalp->v);
6447197Sstephh 				char *buf = MALLOC(len + 1);
6457197Sstephh 
6467197Sstephh 				(void) snprintf(buf, len + 1, "%lldns",
6477197Sstephh 				    serdvalp->v);
6487197Sstephh 				serdvalp->t = STRING;
6497197Sstephh 				serdvalp->v = (uintptr_t)stable(buf);
6507197Sstephh 				FREE(buf);
6517197Sstephh 			}
6527392SScott.Davenport@Sun.COM 
6537197Sstephh 			if (serdvalp->t == UINT64)
6547197Sstephh 				out(O_ALTFP|O_VERB2, " (%llu)", serdvalp->v);
6557197Sstephh 			else
6567197Sstephh 				out(O_ALTFP|O_VERB2, " (\"%s\")",
6577197Sstephh 				    (char *)(uintptr_t)serdvalp->v);
6587197Sstephh 			flt->serdprops = lut_add(flt->serdprops, (void *)str,
6597392SScott.Davenport@Sun.COM 			    (void *)serdvalp, (lut_cmp)strcmp);
6607197Sstephh 		}
6617197Sstephh 		valuep->t = UINT64;
6627197Sstephh 		valuep->v = 1;
6637197Sstephh 		return (1);
6641414Scindi 	} else if (funcname == L_payloadprop_defined) {
6651414Scindi 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
6661414Scindi 		    "payloadprop_defined(\"%s\") ", np->u.quote.s);
6671414Scindi 
6685204Sstephh 		if (arrowp->head->myevent->count == 0) {
6695204Sstephh 			/*
6705204Sstephh 			 * Haven't seen this ereport yet, so must defer
6715204Sstephh 			 */
6725204Sstephh 			out(O_ALTFP|O_VERB2, "ereport not yet seen - defer.");
6735204Sstephh 			return (0);
6745204Sstephh 		} else if (platform_payloadprop(np, NULL)) {
6751414Scindi 			/* platform_payloadprop() returned false */
6761414Scindi 			valuep->v = 0;
6775204Sstephh 			out(O_ALTFP|O_VERB2, "not found.");
6781414Scindi 		} else {
6791414Scindi 			valuep->v = 1;
6801414Scindi 			out(O_ALTFP|O_VERB2, "found.");
6811414Scindi 		}
6821414Scindi 		valuep->t = UINT64;
6831414Scindi 		return (1);
6841414Scindi 	} else if (funcname == L_payloadprop_contains) {
6851414Scindi 		int nvals;
6861414Scindi 		struct evalue *vals;
6871414Scindi 		struct evalue cmpval;
6881414Scindi 
6891414Scindi 		ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t));
6901414Scindi 		ASSERTinfo(np->u.expr.left->t == T_QUOTE,
6911414Scindi 		    ptree_nodetype2str(np->u.expr.left->t));
6921414Scindi 
6931414Scindi 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
6941414Scindi 		    "payloadprop_contains(\"%s\", ",
6951414Scindi 		    np->u.expr.left->u.quote.s);
6961414Scindi 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right);
6972869Sgavinm 		out(O_ALTFP|O_VERB2|O_NONL, ") ");
6981414Scindi 
6991414Scindi 		/* evaluate the expression we're comparing against */
7004436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
7011414Scindi 		    arrowp, try, &cmpval)) {
7021414Scindi 			out(O_ALTFP|O_VERB2|O_NONL,
7035204Sstephh 			    "(cannot eval) ");
7045204Sstephh 			return (0);
7051414Scindi 		} else {
7062869Sgavinm 			switch (cmpval.t) {
7072869Sgavinm 			case UNDEFINED:
7082869Sgavinm 				out(O_ALTFP|O_VERB2, "(undefined type)");
7092869Sgavinm 				break;
7102869Sgavinm 
7112869Sgavinm 			case UINT64:
7121414Scindi 				out(O_ALTFP|O_VERB2,
7131414Scindi 				    "(%llu) ", cmpval.v);
7142869Sgavinm 				break;
7152869Sgavinm 
7162869Sgavinm 			case STRING:
7171414Scindi 				out(O_ALTFP|O_VERB2,
7181717Swesolows 				    "(\"%s\") ", (char *)(uintptr_t)cmpval.v);
7192869Sgavinm 				break;
7202869Sgavinm 
7212869Sgavinm 			case NODEPTR:
7222869Sgavinm 				out(O_ALTFP|O_VERB2|O_NONL, "(");
7232869Sgavinm 				ptree_name_iter(O_ALTFP|O_VERB2|O_NONL,
7242869Sgavinm 				    (struct node *)(uintptr_t)(cmpval.v));
7252869Sgavinm 				out(O_ALTFP|O_VERB2, ") ");
7262869Sgavinm 				break;
7272869Sgavinm 			}
7281414Scindi 		}
7291414Scindi 
7301414Scindi 		/* get the payload values and check for a match */
7311414Scindi 		vals = platform_payloadprop_values(np->u.expr.left->u.quote.s,
7321414Scindi 		    &nvals);
7331414Scindi 		valuep->t = UINT64;
7341414Scindi 		valuep->v = 0;
7355204Sstephh 		if (arrowp->head->myevent->count == 0) {
7365204Sstephh 			/*
7375204Sstephh 			 * Haven't seen this ereport yet, so must defer
7385204Sstephh 			 */
7395204Sstephh 			out(O_ALTFP|O_VERB2, "ereport not yet seen - defer.");
7405204Sstephh 			return (0);
7415204Sstephh 		} else if (nvals == 0) {
7421414Scindi 			out(O_ALTFP|O_VERB2, "not found.");
7435204Sstephh 			return (1);
7441414Scindi 		} else {
7451414Scindi 			struct evalue preval;
7461414Scindi 			int i;
7471414Scindi 
7481414Scindi 			out(O_ALTFP|O_VERB2|O_NONL, "found %d values ", nvals);
7491414Scindi 
7501414Scindi 			for (i = 0; i < nvals; i++) {
7511414Scindi 
7521414Scindi 				preval.t = vals[i].t;
7531414Scindi 				preval.v = vals[i].v;
7541414Scindi 
7551414Scindi 				if (check_expr_args(&vals[i], &cmpval,
7561414Scindi 				    UNDEFINED, np))
7571414Scindi 					continue;
7581414Scindi 
7591414Scindi 				/*
7601414Scindi 				 * If we auto-converted the value to a
7611414Scindi 				 * string, we need to free the
7621414Scindi 				 * original tree value.
7631414Scindi 				 */
7641414Scindi 				if (preval.t == NODEPTR &&
7651717Swesolows 				    ((struct node *)(uintptr_t)(preval.v))->t ==
7661717Swesolows 				    T_NAME) {
7671717Swesolows 					tree_free((struct node *)(uintptr_t)
7681717Swesolows 					    preval.v);
7691414Scindi 				}
7701414Scindi 
7711414Scindi 				if (vals[i].v == cmpval.v) {
7721414Scindi 					valuep->v = 1;
7731414Scindi 					break;
7741414Scindi 				}
7751414Scindi 			}
776186Sdb35262 
7771414Scindi 			if (valuep->v)
7781414Scindi 				out(O_ALTFP|O_VERB2, "match.");
7791414Scindi 			else
7801414Scindi 				out(O_ALTFP|O_VERB2, "no match.");
781186Sdb35262 
7821414Scindi 			for (i = 0; i < nvals; i++) {
7831414Scindi 				if (vals[i].t == NODEPTR) {
7841717Swesolows 					tree_free((struct node *)(uintptr_t)
7851717Swesolows 					    vals[i].v);
7861414Scindi 					break;
7871414Scindi 				}
788186Sdb35262 			}
7891414Scindi 			FREE(vals);
7901414Scindi 		}
7911414Scindi 		return (1);
7921414Scindi 	} else if (funcname == L_confcall) {
7931414Scindi 		return (!platform_confcall(np, globals, croot, arrowp, valuep));
7940Sstevel@tonic-gate 	} else
7950Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
7960Sstevel@tonic-gate 		    "eval_func: unexpected func: %s", funcname);
7970Sstevel@tonic-gate 	/*NOTREACHED*/
7981717Swesolows 	return (0);
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate 
8014436Sstephh /*
8024436Sstephh  * defines for u.expr.temp - these are used for T_OR and T_AND so that if
8034436Sstephh  * we worked out that part of the expression was true or false during an
8044436Sstephh  * earlier eval_expr, then we don't need to dup that part.
8054436Sstephh  */
8060Sstevel@tonic-gate 
8074436Sstephh #define	EXPR_TEMP_BOTH_UNK	0
8084436Sstephh #define	EXPR_TEMP_LHS_UNK	1
8094436Sstephh #define	EXPR_TEMP_RHS_UNK	2
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate static struct node *
8124436Sstephh eval_dup(struct node *np, struct lut *ex, struct node *events[])
8130Sstevel@tonic-gate {
8140Sstevel@tonic-gate 	struct node *newnp;
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	if (np == NULL)
8170Sstevel@tonic-gate 		return (NULL);
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	switch (np->t) {
8200Sstevel@tonic-gate 	case T_GLOBID:
8210Sstevel@tonic-gate 		return (tree_globid(np->u.globid.s, np->file, np->line));
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	case T_ASSIGN:
8240Sstevel@tonic-gate 	case T_CONDIF:
8250Sstevel@tonic-gate 	case T_CONDELSE:
8260Sstevel@tonic-gate 	case T_NE:
8270Sstevel@tonic-gate 	case T_EQ:
8280Sstevel@tonic-gate 	case T_LT:
8290Sstevel@tonic-gate 	case T_LE:
8300Sstevel@tonic-gate 	case T_GT:
8310Sstevel@tonic-gate 	case T_GE:
8320Sstevel@tonic-gate 	case T_BITAND:
8330Sstevel@tonic-gate 	case T_BITOR:
8340Sstevel@tonic-gate 	case T_BITXOR:
8350Sstevel@tonic-gate 	case T_BITNOT:
8360Sstevel@tonic-gate 	case T_LSHIFT:
8370Sstevel@tonic-gate 	case T_RSHIFT:
8380Sstevel@tonic-gate 	case T_NOT:
8390Sstevel@tonic-gate 	case T_ADD:
8400Sstevel@tonic-gate 	case T_SUB:
8410Sstevel@tonic-gate 	case T_MUL:
8420Sstevel@tonic-gate 	case T_DIV:
8430Sstevel@tonic-gate 	case T_MOD:
8440Sstevel@tonic-gate 		return (tree_expr(np->t,
8454436Sstephh 		    eval_dup(np->u.expr.left, ex, events),
8464436Sstephh 		    eval_dup(np->u.expr.right, ex, events)));
8474436Sstephh 	case T_LIST:
8484436Sstephh 	case T_AND:
8494436Sstephh 		switch (np->u.expr.temp) {
8504436Sstephh 		case EXPR_TEMP_LHS_UNK:
8514436Sstephh 			return (eval_dup(np->u.expr.left, ex, events));
8524436Sstephh 		case EXPR_TEMP_RHS_UNK:
8534436Sstephh 			return (eval_dup(np->u.expr.right, ex, events));
8544436Sstephh 		default:
8554436Sstephh 			return (tree_expr(np->t,
8564436Sstephh 			    eval_dup(np->u.expr.left, ex, events),
8574436Sstephh 			    eval_dup(np->u.expr.right, ex, events)));
8584436Sstephh 		}
8594436Sstephh 
8604436Sstephh 	case T_OR:
8614436Sstephh 		switch (np->u.expr.temp) {
8624436Sstephh 		case EXPR_TEMP_LHS_UNK:
8634436Sstephh 			return (eval_dup(np->u.expr.left, ex, events));
8644436Sstephh 		case EXPR_TEMP_RHS_UNK:
8654436Sstephh 			return (eval_dup(np->u.expr.right, ex, events));
8664436Sstephh 		default:
8674436Sstephh 			return (tree_expr(T_OR,
8684436Sstephh 			    eval_dup(np->u.expr.left, ex, events),
8694436Sstephh 			    eval_dup(np->u.expr.right, ex, events)));
8704436Sstephh 		}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	case T_NAME: {
8730Sstevel@tonic-gate 		struct iterinfo *iterinfop;
8744436Sstephh 		int got_matchf = 0;
8754436Sstephh 		int got_matcht = 0;
8764436Sstephh 		struct evalue value;
8774436Sstephh 		struct node *np1f, *np2f, *np1t, *np2t, *retp = NULL;
8784436Sstephh 		struct node *npstart, *npcont, *npend, *npref, *newnp, *nprest;
8790Sstevel@tonic-gate 
8804436Sstephh 		/*
8814436Sstephh 		 * Check if we already have a match of the nonwildcarded path
8824436Sstephh 		 * in oldepname (check both to and from events).
8834436Sstephh 		 */
8844436Sstephh 		for (np1f = np, np2f = events[0]->u.event.oldepname;
8854436Sstephh 		    np1f != NULL && np2f != NULL;
8864436Sstephh 		    np1f = np1f->u.name.next, np2f = np2f->u.name.next) {
8874436Sstephh 			if (strcmp(np1f->u.name.s, np2f->u.name.s) != 0)
8884436Sstephh 				break;
8894436Sstephh 			if (np1f->u.name.child->t != np2f->u.name.child->t)
8904436Sstephh 				break;
8914436Sstephh 			if (np1f->u.name.child->t == T_NUM &&
8924436Sstephh 			    np1f->u.name.child->u.ull !=
8934436Sstephh 			    np2f->u.name.child->u.ull)
8944436Sstephh 				break;
8954436Sstephh 			if (np1f->u.name.child->t == T_NAME &&
8964436Sstephh 			    strcmp(np1f->u.name.child->u.name.s,
8974436Sstephh 			    np2f->u.name.child->u.name.s) != 0)
8984436Sstephh 				break;
8994436Sstephh 			got_matchf++;
9004436Sstephh 		}
9014436Sstephh 		for (np1t = np, np2t = events[1]->u.event.oldepname;
9024436Sstephh 		    np1t != NULL && np2t != NULL;
9034436Sstephh 		    np1t = np1t->u.name.next, np2t = np2t->u.name.next) {
9044436Sstephh 			if (strcmp(np1t->u.name.s, np2t->u.name.s) != 0)
9054436Sstephh 				break;
9064436Sstephh 			if (np1t->u.name.child->t != np2t->u.name.child->t)
9074436Sstephh 				break;
9084436Sstephh 			if (np1t->u.name.child->t == T_NUM &&
9094436Sstephh 			    np1t->u.name.child->u.ull !=
9104436Sstephh 			    np2t->u.name.child->u.ull)
9114436Sstephh 				break;
9124436Sstephh 			if (np1t->u.name.child->t == T_NAME &&
9134436Sstephh 			    strcmp(np1t->u.name.child->u.name.s,
9144436Sstephh 			    np2t->u.name.child->u.name.s) != 0)
9154436Sstephh 				break;
9164436Sstephh 			got_matcht++;
9174436Sstephh 		}
9184436Sstephh 		nprest = np;
9194436Sstephh 		if (got_matchf || got_matcht) {
9204436Sstephh 			/*
9214436Sstephh 			 * so we are wildcarding. Copy ewname in full, plus
9224436Sstephh 			 * matching section of oldepname. Use whichever gives
9234436Sstephh 			 * the closest match.
9244436Sstephh 			 */
9254436Sstephh 			if (got_matchf > got_matcht) {
9264436Sstephh 				npstart = events[0]->u.event.ewname;
9274436Sstephh 				npcont = events[0]->u.event.oldepname;
9284436Sstephh 				npend = np2f;
9294436Sstephh 				nprest = np1f;
9304436Sstephh 			} else {
9314436Sstephh 				npstart = events[1]->u.event.ewname;
9324436Sstephh 				npcont = events[1]->u.event.oldepname;
9334436Sstephh 				npend = np2t;
9344436Sstephh 				nprest = np1t;
9354436Sstephh 			}
9364436Sstephh 			for (npref = npstart; npref != NULL;
9374436Sstephh 			    npref = npref->u.name.next) {
9384436Sstephh 				newnp = newnode(T_NAME, np->file, np->line);
9394436Sstephh 				newnp->u.name.t = npref->u.name.t;
9404436Sstephh 				newnp->u.name.s = npref->u.name.s;
9414436Sstephh 				newnp->u.name.last = newnp;
9424436Sstephh 				newnp->u.name.it = npref->u.name.it;
9434436Sstephh 				newnp->u.name.cp = npref->u.name.cp;
9444436Sstephh 				newnp->u.name.child =
9454436Sstephh 				    newnode(T_NUM, np->file, np->line);
9464436Sstephh 				if (eval_expr(npref->u.name.child, ex, events,
9470Sstevel@tonic-gate 				    NULL, NULL, NULL, 1, &value) == 0 ||
9480Sstevel@tonic-gate 				    value.t != UINT64) {
9490Sstevel@tonic-gate 					outfl(O_DIE, np->file, np->line,
9500Sstevel@tonic-gate 					    "eval_dup: could not resolve "
9510Sstevel@tonic-gate 					    "iterator of %s", np->u.name.s);
9520Sstevel@tonic-gate 				}
9534436Sstephh 				newnp->u.name.child->u.ull = value.v;
9544436Sstephh 				if (retp == NULL) {
9554436Sstephh 					retp = newnp;
9564436Sstephh 				} else {
9574436Sstephh 					retp->u.name.last->u.name.next = newnp;
9584436Sstephh 					retp->u.name.last = newnp;
9594436Sstephh 				}
9600Sstevel@tonic-gate 			}
9614436Sstephh 			for (npref = npcont; npref != NULL && npref != npend;
9624436Sstephh 			    npref = npref->u.name.next) {
9634436Sstephh 				newnp = newnode(T_NAME, np->file, np->line);
9644436Sstephh 				newnp->u.name.t = npref->u.name.t;
9654436Sstephh 				newnp->u.name.s = npref->u.name.s;
9664436Sstephh 				newnp->u.name.last = newnp;
9674436Sstephh 				newnp->u.name.it = npref->u.name.it;
9684436Sstephh 				newnp->u.name.cp = npref->u.name.cp;
9694436Sstephh 				newnp->u.name.child =
9704436Sstephh 				    newnode(T_NUM, np->file, np->line);
9714436Sstephh 				if (eval_expr(npref->u.name.child, ex, events,
9724436Sstephh 				    NULL, NULL, NULL, 1, &value) == 0 ||
9734436Sstephh 				    value.t != UINT64) {
9744436Sstephh 					outfl(O_DIE, np->file, np->line,
9754436Sstephh 					    "eval_dup: could not resolve "
9764436Sstephh 					    "iterator of %s", np->u.name.s);
9774436Sstephh 				}
9784436Sstephh 				newnp->u.name.child->u.ull = value.v;
9794436Sstephh 				if (retp == NULL) {
9804436Sstephh 					retp = newnp;
9814436Sstephh 				} else {
9824436Sstephh 					retp->u.name.last->u.name.next = newnp;
9834436Sstephh 					retp->u.name.last = newnp;
9844436Sstephh 				}
9854436Sstephh 			}
9864436Sstephh 		} else {
9874436Sstephh 			/*
9884436Sstephh 			 * not wildcarding - check if explicit iterator
9894436Sstephh 			 */
9904436Sstephh 			iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
9914436Sstephh 			if (iterinfop != NULL) {
9924436Sstephh 				/* explicit iterator; not part of pathname */
9934436Sstephh 				newnp = newnode(T_NUM, np->file, np->line);
9944436Sstephh 				newnp->u.ull = iterinfop->num;
9950Sstevel@tonic-gate 				return (newnp);
9960Sstevel@tonic-gate 			}
9970Sstevel@tonic-gate 		}
9984436Sstephh 
9994436Sstephh 		/*
10004436Sstephh 		 * finally, whether wildcarding or not, we need to copy the
10014436Sstephh 		 * remaining part of the path (if any). This must be defined
10024436Sstephh 		 * absolutely (no more expansion/wildcarding).
10034436Sstephh 		 */
10044436Sstephh 		for (npref = nprest; npref != NULL;
10054436Sstephh 		    npref = npref->u.name.next) {
10064436Sstephh 			newnp = newnode(T_NAME, np->file, np->line);
10074436Sstephh 			newnp->u.name.t = npref->u.name.t;
10084436Sstephh 			newnp->u.name.s = npref->u.name.s;
10094436Sstephh 			newnp->u.name.last = newnp;
10104436Sstephh 			newnp->u.name.it = npref->u.name.it;
10114436Sstephh 			newnp->u.name.cp = npref->u.name.cp;
10124436Sstephh 			newnp->u.name.child =
10134436Sstephh 			    newnode(T_NUM, np->file, np->line);
10144436Sstephh 			if (eval_expr(npref->u.name.child, ex, events,
10154436Sstephh 			    NULL, NULL, NULL, 1, &value) == 0 ||
10164436Sstephh 			    value.t != UINT64) {
10174436Sstephh 				outfl(O_DIE, np->file, np->line,
10184436Sstephh 				    "eval_dup: could not resolve "
10194436Sstephh 				    "iterator of %s", np->u.name.s);
10204436Sstephh 			}
10214436Sstephh 			newnp->u.name.child->u.ull = value.v;
10224436Sstephh 			if (retp == NULL) {
10234436Sstephh 				retp = newnp;
10244436Sstephh 			} else {
10254436Sstephh 				retp->u.name.last->u.name.next = newnp;
10264436Sstephh 				retp->u.name.last = newnp;
10274436Sstephh 			}
10284436Sstephh 		}
10294436Sstephh 		return (retp);
10300Sstevel@tonic-gate 	}
10310Sstevel@tonic-gate 
10321414Scindi 	case T_EVENT:
10331414Scindi 		newnp = newnode(T_NAME, np->file, np->line);
10341414Scindi 
10351414Scindi 		newnp->u.name.t = np->u.event.ename->u.name.t;
10361414Scindi 		newnp->u.name.s = np->u.event.ename->u.name.s;
10371414Scindi 		newnp->u.name.it = np->u.event.ename->u.name.it;
10381414Scindi 		newnp->u.name.last = newnp;
10391414Scindi 
10401414Scindi 		return (tree_event(newnp,
10414436Sstephh 		    eval_dup(np->u.event.epname, ex, events),
10424436Sstephh 		    eval_dup(np->u.event.eexprlist, ex, events)));
10431414Scindi 
10440Sstevel@tonic-gate 	case T_FUNC:
10450Sstevel@tonic-gate 		return (tree_func(np->u.func.s,
10464436Sstephh 		    eval_dup(np->u.func.arglist, ex, events),
10470Sstevel@tonic-gate 		    np->file, np->line));
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 	case T_QUOTE:
10500Sstevel@tonic-gate 		newnp = newnode(T_QUOTE, np->file, np->line);
10510Sstevel@tonic-gate 		newnp->u.quote.s = np->u.quote.s;
10520Sstevel@tonic-gate 		return (newnp);
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	case T_NUM:
10550Sstevel@tonic-gate 		newnp = newnode(T_NUM, np->file, np->line);
10560Sstevel@tonic-gate 		newnp->u.ull = np->u.ull;
10570Sstevel@tonic-gate 		return (newnp);
10580Sstevel@tonic-gate 
10597197Sstephh 	case T_TIMEVAL:
10607197Sstephh 		newnp = newnode(T_TIMEVAL, np->file, np->line);
10617197Sstephh 		newnp->u.ull = np->u.ull;
10627197Sstephh 		return (newnp);
10637197Sstephh 
10640Sstevel@tonic-gate 	default:
10650Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
10660Sstevel@tonic-gate 		    "eval_dup: unexpected node type: %s",
10670Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
10680Sstevel@tonic-gate 	}
10690Sstevel@tonic-gate 	/*NOTREACHED*/
10701717Swesolows 	return (0);
10710Sstevel@tonic-gate }
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate  * eval_potential -- see if constraint is potentially true
10750Sstevel@tonic-gate  *
10760Sstevel@tonic-gate  * this function is used at instance tree creation time to see if
10770Sstevel@tonic-gate  * any constraints are already known to be false.  if this function
10780Sstevel@tonic-gate  * returns false, then the constraint will always be false and there's
10790Sstevel@tonic-gate  * no need to include the propagation arrow in the instance tree.
10800Sstevel@tonic-gate  *
10810Sstevel@tonic-gate  * if this routine returns true, either the constraint is known to
10820Sstevel@tonic-gate  * be always true (so there's no point in attaching the constraint
10830Sstevel@tonic-gate  * to the propagation arrow in the instance tree), or the constraint
10840Sstevel@tonic-gate  * contains "deferred" expressions like global variables or poller calls
10850Sstevel@tonic-gate  * and so it must be evaluated during calls to fme_eval().  in this last
10860Sstevel@tonic-gate  * case, where a constraint needs to be attached to the propagation arrow
10870Sstevel@tonic-gate  * in the instance tree, this routine returns a newly created constraint
10880Sstevel@tonic-gate  * in *newc where all the non-deferred things have been filled in.
10890Sstevel@tonic-gate  *
10900Sstevel@tonic-gate  * so in summary:
10910Sstevel@tonic-gate  *
10920Sstevel@tonic-gate  *	return of false: constraint can never be true, *newc will be NULL.
10930Sstevel@tonic-gate  *
10940Sstevel@tonic-gate  *	return of true with *newc unchanged: constraint will always be true.
10950Sstevel@tonic-gate  *
10960Sstevel@tonic-gate  *	return of true with *newc changed: use new constraint in *newc.
10970Sstevel@tonic-gate  *
10980Sstevel@tonic-gate  * the lookup table for all explicit iterators, ex, is passed in.
10990Sstevel@tonic-gate  *
11000Sstevel@tonic-gate  * *newc can either be NULL on entry, or if can contain constraints from
11010Sstevel@tonic-gate  * previous calls to eval_potential() (i.e. for building up an instance
11020Sstevel@tonic-gate  * tree constraint from several potential constraints).  if *newc already
11030Sstevel@tonic-gate  * contains constraints, anything added to it will be joined by adding
11040Sstevel@tonic-gate  * a T_AND node at the top of *newc.
11050Sstevel@tonic-gate  */
11060Sstevel@tonic-gate int
11074436Sstephh eval_potential(struct node *np, struct lut *ex, struct node *events[],
11082318Sstephh 	    struct node **newc, struct config *croot)
11090Sstevel@tonic-gate {
11100Sstevel@tonic-gate 	struct node *newnp;
11110Sstevel@tonic-gate 	struct evalue value;
11120Sstevel@tonic-gate 
11134436Sstephh 	if (eval_expr(np, ex, events, NULL, croot, NULL, 1, &value) == 0) {
11140Sstevel@tonic-gate 		/*
11150Sstevel@tonic-gate 		 * couldn't eval expression because
11160Sstevel@tonic-gate 		 * it contains deferred items.  make
11170Sstevel@tonic-gate 		 * a duplicate expression with all the
11180Sstevel@tonic-gate 		 * non-deferred items expanded.
11190Sstevel@tonic-gate 		 */
11204436Sstephh 		newnp = eval_dup(np, ex, events);
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 		if (*newc == NULL) {
11230Sstevel@tonic-gate 			/*
11240Sstevel@tonic-gate 			 * constraint is potentially true if deferred
11250Sstevel@tonic-gate 			 * expression in newnp is true.  *newc was NULL
11260Sstevel@tonic-gate 			 * so new constraint is just the one in newnp.
11270Sstevel@tonic-gate 			 */
11280Sstevel@tonic-gate 			*newc = newnp;
11290Sstevel@tonic-gate 			return (1);
11300Sstevel@tonic-gate 		} else {
11310Sstevel@tonic-gate 			/*
11320Sstevel@tonic-gate 			 * constraint is potentially true if deferred
11330Sstevel@tonic-gate 			 * expression in newnp is true.  *newc already
11340Sstevel@tonic-gate 			 * contained a constraint so add an AND with the
11350Sstevel@tonic-gate 			 * constraint in newnp.
11360Sstevel@tonic-gate 			 */
11370Sstevel@tonic-gate 			*newc = tree_expr(T_AND, *newc, newnp);
11380Sstevel@tonic-gate 			return (1);
11390Sstevel@tonic-gate 		}
11400Sstevel@tonic-gate 	} else if (value.t == UNDEFINED) {
11410Sstevel@tonic-gate 		/* constraint can never be true */
11420Sstevel@tonic-gate 		return (0);
11430Sstevel@tonic-gate 	} else if (value.t == UINT64 && value.v == 0) {
11440Sstevel@tonic-gate 		/* constraint can never be true */
11450Sstevel@tonic-gate 		return (0);
11460Sstevel@tonic-gate 	} else {
11470Sstevel@tonic-gate 		/* constraint is always true (nothing deferred to eval) */
11480Sstevel@tonic-gate 		return (1);
11490Sstevel@tonic-gate 	}
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate static int
11530Sstevel@tonic-gate check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype,
11540Sstevel@tonic-gate 		struct node *np)
11550Sstevel@tonic-gate {
11561414Scindi 	/* auto-convert T_NAMES to strings */
11571717Swesolows 	if (lp->t == NODEPTR && ((struct node *)(uintptr_t)(lp->v))->t ==
11581717Swesolows 	    T_NAME) {
11591717Swesolows 		char *s = ipath2str(NULL,
11601717Swesolows 		    ipath((struct node *)(uintptr_t)lp->v));
11611414Scindi 		lp->t = STRING;
11621717Swesolows 		lp->v = (uintptr_t)stable(s);
11631414Scindi 		FREE(s);
11641414Scindi 		out(O_ALTFP|O_VERB2, "convert lhs path to \"%s\"",
11651717Swesolows 		    (char *)(uintptr_t)lp->v);
11661414Scindi 	}
11671414Scindi 	if (rp != NULL &&
11681717Swesolows 	    rp->t == NODEPTR && ((struct node *)(uintptr_t)(rp->v))->t ==
11691717Swesolows 	    T_NAME) {
11701717Swesolows 		char *s = ipath2str(NULL,
11711717Swesolows 		    ipath((struct node *)(uintptr_t)rp->v));
11721414Scindi 		rp->t = STRING;
11731717Swesolows 		rp->v = (uintptr_t)stable(s);
11741414Scindi 		FREE(s);
11751414Scindi 		out(O_ALTFP|O_VERB2, "convert rhs path to \"%s\"",
11761717Swesolows 		    (char *)(uintptr_t)rp->v);
11771414Scindi 	}
11781414Scindi 
11791414Scindi 	/* auto-convert strings to numbers */
11801414Scindi 	if (dtype == UINT64) {
11811414Scindi 		if (lp->t == STRING) {
11821414Scindi 			lp->t = UINT64;
11831717Swesolows 			lp->v = strtoull((char *)(uintptr_t)lp->v, NULL, 0);
11841414Scindi 		}
11851414Scindi 		if (rp != NULL && rp->t == STRING) {
11861414Scindi 			rp->t = UINT64;
11871717Swesolows 			rp->v = strtoull((char *)(uintptr_t)rp->v, NULL, 0);
11881414Scindi 		}
11891414Scindi 	}
11901414Scindi 
11910Sstevel@tonic-gate 	if (dtype != UNDEFINED && lp->t != dtype) {
11924436Sstephh 		outfl(O_DIE, np->file, np->line,
11934436Sstephh 		    "invalid datatype of argument for operation %s",
11944436Sstephh 		    ptree_nodetype2str(np->t));
11954436Sstephh 		/* NOTREACHED */
11960Sstevel@tonic-gate 		return (1);
11970Sstevel@tonic-gate 	}
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	if (rp != NULL && lp->t != rp->t) {
12004436Sstephh 		outfl(O_DIE, np->file, np->line,
12014436Sstephh 		    "mismatch in datatype of arguments for operation %s",
12024436Sstephh 		    ptree_nodetype2str(np->t));
12034436Sstephh 		/* NOTREACHED */
12040Sstevel@tonic-gate 		return (1);
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	return (0);
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate /*
12110Sstevel@tonic-gate  * eval_expr -- evaluate expression into *valuep
12120Sstevel@tonic-gate  *
12130Sstevel@tonic-gate  * the meaning of the return value depends on the input value of try.
12140Sstevel@tonic-gate  *
12150Sstevel@tonic-gate  * for try == 1: if any deferred items are encounted, bail out and return
12160Sstevel@tonic-gate  * false.  returns true if we made it through entire expression without
12170Sstevel@tonic-gate  * hitting any deferred items.
12180Sstevel@tonic-gate  *
12190Sstevel@tonic-gate  * for try == 0: return true if all operations were performed successfully.
12200Sstevel@tonic-gate  * return false if otherwise.  for example, any of the following conditions
12210Sstevel@tonic-gate  * will result in a false return value:
12220Sstevel@tonic-gate  *   - attempted use of an uninitialized global variable
12230Sstevel@tonic-gate  *   - failure in function evaluation
12240Sstevel@tonic-gate  *   - illegal arithmetic operation (argument out of range)
12250Sstevel@tonic-gate  */
12260Sstevel@tonic-gate int
12274436Sstephh eval_expr(struct node *np, struct lut *ex, struct node *events[],
12280Sstevel@tonic-gate 	struct lut **globals, struct config *croot, struct arrow *arrowp,
12290Sstevel@tonic-gate 	int try, struct evalue *valuep)
12300Sstevel@tonic-gate {
12310Sstevel@tonic-gate 	struct evalue *gval;
12320Sstevel@tonic-gate 	struct evalue lval;
12330Sstevel@tonic-gate 	struct evalue rval;
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	if (np == NULL) {
12360Sstevel@tonic-gate 		valuep->t = UINT64;
12370Sstevel@tonic-gate 		valuep->v = 1;	/* no constraint means "true" */
12380Sstevel@tonic-gate 		return (1);
12390Sstevel@tonic-gate 	}
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	valuep->t = UNDEFINED;
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	switch (np->t) {
12440Sstevel@tonic-gate 	case T_GLOBID:
12450Sstevel@tonic-gate 		if (try)
12460Sstevel@tonic-gate 			return (0);
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 		/*
12490Sstevel@tonic-gate 		 * only handle case of getting (and not setting) the value
12500Sstevel@tonic-gate 		 * of a global variable
12510Sstevel@tonic-gate 		 */
12520Sstevel@tonic-gate 		gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL);
12530Sstevel@tonic-gate 		if (gval == NULL) {
12540Sstevel@tonic-gate 			return (0);
12550Sstevel@tonic-gate 		} else {
12560Sstevel@tonic-gate 			valuep->t = gval->t;
12570Sstevel@tonic-gate 			valuep->v = gval->v;
12580Sstevel@tonic-gate 			return (1);
12590Sstevel@tonic-gate 		}
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 	case T_ASSIGN:
12620Sstevel@tonic-gate 		if (try)
12630Sstevel@tonic-gate 			return (0);
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 		/*
12660Sstevel@tonic-gate 		 * first evaluate rhs, then try to store value in lhs which
12670Sstevel@tonic-gate 		 * should be a global variable
12680Sstevel@tonic-gate 		 */
12694436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
12704436Sstephh 		    arrowp, try, &rval))
12710Sstevel@tonic-gate 			return (0);
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 		ASSERT(np->u.expr.left->t == T_GLOBID);
12740Sstevel@tonic-gate 		gval = lut_lookup(*globals,
12754436Sstephh 		    (void *)np->u.expr.left->u.globid.s, NULL);
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 		if (gval == NULL) {
12780Sstevel@tonic-gate 			gval = MALLOC(sizeof (*gval));
12790Sstevel@tonic-gate 			*globals = lut_add(*globals,
12804436Sstephh 			    (void *) np->u.expr.left->u.globid.s, gval, NULL);
12810Sstevel@tonic-gate 		}
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 		gval->t = rval.t;
12840Sstevel@tonic-gate 		gval->v = rval.v;
12851414Scindi 
12861414Scindi 		if (gval->t == UINT64) {
12871414Scindi 			out(O_ALTFP|O_VERB2,
12881414Scindi 			    "assign $%s=%llu",
12891414Scindi 			    np->u.expr.left->u.globid.s, gval->v);
12901414Scindi 		} else {
12911414Scindi 			out(O_ALTFP|O_VERB2,
12921414Scindi 			    "assign $%s=\"%s\"",
12931717Swesolows 			    np->u.expr.left->u.globid.s,
12941717Swesolows 			    (char *)(uintptr_t)gval->v);
12951414Scindi 		}
12961414Scindi 
12971414Scindi 		/*
12981414Scindi 		 * but always return true -- an assignment should not
12991414Scindi 		 * cause a constraint to be false.
13001414Scindi 		 */
13011414Scindi 		valuep->t = UINT64;
13021414Scindi 		valuep->v = 1;
13030Sstevel@tonic-gate 		return (1);
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	case T_EQ:
13060Sstevel@tonic-gate #define	IMPLICIT_ASSIGN_IN_EQ
13070Sstevel@tonic-gate #ifdef IMPLICIT_ASSIGN_IN_EQ
13080Sstevel@tonic-gate 		/*
13090Sstevel@tonic-gate 		 * if lhs is an uninitialized global variable, perform
13100Sstevel@tonic-gate 		 * an assignment.
13110Sstevel@tonic-gate 		 *
13120Sstevel@tonic-gate 		 * one insidious side effect of implicit assignment is
13130Sstevel@tonic-gate 		 * that the "==" operator does not return a Boolean if
13140Sstevel@tonic-gate 		 * implicit assignment was performed.
13150Sstevel@tonic-gate 		 */
13160Sstevel@tonic-gate 		if (try == 0 &&
13170Sstevel@tonic-gate 		    np->u.expr.left->t == T_GLOBID &&
13180Sstevel@tonic-gate 		    (gval = lut_lookup(*globals,
13194436Sstephh 		    (void *)np->u.expr.left->u.globid.s, NULL)) == NULL) {
13204436Sstephh 			if (!eval_expr(np->u.expr.right, ex, events, globals,
13214436Sstephh 			    croot, arrowp, try, &rval))
13220Sstevel@tonic-gate 				return (0);
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 			gval = MALLOC(sizeof (*gval));
13250Sstevel@tonic-gate 			*globals = lut_add(*globals,
13264436Sstephh 			    (void *) np->u.expr.left->u.globid.s,
13274436Sstephh 			    gval, NULL);
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 			gval->t = rval.t;
13300Sstevel@tonic-gate 			gval->v = rval.v;
13310Sstevel@tonic-gate 			valuep->t = rval.t;
13320Sstevel@tonic-gate 			valuep->v = rval.v;
13330Sstevel@tonic-gate 			return (1);
13340Sstevel@tonic-gate 		}
13350Sstevel@tonic-gate #endif  /* IMPLICIT_ASSIGN_IN_EQ */
13360Sstevel@tonic-gate 
13374436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
13384436Sstephh 		    arrowp, try, &lval))
13394436Sstephh 			return (0);
13404436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
13414436Sstephh 		    arrowp, try, &rval))
13420Sstevel@tonic-gate 			return (0);
13434436Sstephh 		if (rval.t == UINT64 || lval.t == UINT64) {
13444436Sstephh 			if (check_expr_args(&lval, &rval, UINT64, np))
13454436Sstephh 				return (0);
13464436Sstephh 		} else {
13474436Sstephh 			if (check_expr_args(&lval, &rval, UNDEFINED, np))
13484436Sstephh 				return (0);
13494436Sstephh 		}
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 		valuep->t = UINT64;
13520Sstevel@tonic-gate 		valuep->v = (lval.v == rval.v);
13530Sstevel@tonic-gate 		return (1);
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	case T_LT:
13564436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
13574436Sstephh 		    arrowp, try, &lval))
13580Sstevel@tonic-gate 			return (0);
13594436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
13604436Sstephh 		    arrowp, try, &rval))
13610Sstevel@tonic-gate 			return (0);
13621414Scindi 		if (check_expr_args(&lval, &rval, UINT64, np))
13630Sstevel@tonic-gate 			return (0);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 		valuep->t = UINT64;
13660Sstevel@tonic-gate 		valuep->v = (lval.v < rval.v);
13670Sstevel@tonic-gate 		return (1);
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	case T_LE:
13704436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
13714436Sstephh 		    arrowp, try, &lval))
13720Sstevel@tonic-gate 			return (0);
13734436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
13744436Sstephh 		    arrowp, try, &rval))
13750Sstevel@tonic-gate 			return (0);
13761414Scindi 		if (check_expr_args(&lval, &rval, UINT64, np))
13770Sstevel@tonic-gate 			return (0);
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 		valuep->t = UINT64;
13800Sstevel@tonic-gate 		valuep->v = (lval.v <= rval.v);
13810Sstevel@tonic-gate 		return (1);
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 	case T_GT:
13844436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
13854436Sstephh 		    arrowp, try, &lval))
13860Sstevel@tonic-gate 			return (0);
13874436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
13884436Sstephh 		    arrowp, try, &rval))
13890Sstevel@tonic-gate 			return (0);
13901414Scindi 		if (check_expr_args(&lval, &rval, UINT64, np))
13910Sstevel@tonic-gate 			return (0);
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 		valuep->t = UINT64;
13940Sstevel@tonic-gate 		valuep->v = (lval.v > rval.v);
13950Sstevel@tonic-gate 		return (1);
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 	case T_GE:
13984436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
13994436Sstephh 		    arrowp, try, &lval))
14000Sstevel@tonic-gate 			return (0);
14014436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
14024436Sstephh 		    arrowp, try, &rval))
14030Sstevel@tonic-gate 			return (0);
14041414Scindi 		if (check_expr_args(&lval, &rval, UINT64, np))
14050Sstevel@tonic-gate 			return (0);
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 		valuep->t = UINT64;
14080Sstevel@tonic-gate 		valuep->v = (lval.v >= rval.v);
14090Sstevel@tonic-gate 		return (1);
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	case T_BITAND:
14124436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
14134436Sstephh 		    arrowp, try, &lval))
14140Sstevel@tonic-gate 			return (0);
14154436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
14164436Sstephh 		    arrowp, try, &rval))
14170Sstevel@tonic-gate 			return (0);
14180Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
14190Sstevel@tonic-gate 			return (0);
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 		valuep->t = lval.t;
14220Sstevel@tonic-gate 		valuep->v = (lval.v & rval.v);
14230Sstevel@tonic-gate 		return (1);
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate 	case T_BITOR:
14264436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
14274436Sstephh 		    arrowp, try, &lval))
14280Sstevel@tonic-gate 			return (0);
14294436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
14304436Sstephh 		    arrowp, try, &rval))
14310Sstevel@tonic-gate 			return (0);
14320Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
14330Sstevel@tonic-gate 			return (0);
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 		valuep->t = lval.t;
14360Sstevel@tonic-gate 		valuep->v = (lval.v | rval.v);
14370Sstevel@tonic-gate 		return (1);
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	case T_BITXOR:
14404436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
14414436Sstephh 		    arrowp, try, &lval))
14420Sstevel@tonic-gate 			return (0);
14434436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
14444436Sstephh 		    arrowp, try, &rval))
14450Sstevel@tonic-gate 			return (0);
14460Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
14470Sstevel@tonic-gate 			return (0);
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 		valuep->t = lval.t;
14500Sstevel@tonic-gate 		valuep->v = (lval.v ^ rval.v);
14510Sstevel@tonic-gate 		return (1);
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	case T_BITNOT:
14544436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
14554436Sstephh 		    arrowp, try, &lval))
14560Sstevel@tonic-gate 			return (0);
14570Sstevel@tonic-gate 		ASSERT(np->u.expr.right == NULL);
14580Sstevel@tonic-gate 		if (check_expr_args(&lval, NULL, UINT64, np))
14590Sstevel@tonic-gate 			return (0);
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 		valuep->t = UINT64;
14620Sstevel@tonic-gate 		valuep->v = ~ lval.v;
14630Sstevel@tonic-gate 		return (1);
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	case T_LSHIFT:
14664436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
14674436Sstephh 		    arrowp, try, &lval))
14680Sstevel@tonic-gate 			return (0);
14694436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
14704436Sstephh 		    arrowp, try, &rval))
14710Sstevel@tonic-gate 			return (0);
14720Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
14730Sstevel@tonic-gate 			return (0);
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 		valuep->t = UINT64;
14760Sstevel@tonic-gate 		valuep->v = (lval.v << rval.v);
14770Sstevel@tonic-gate 		return (1);
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 	case T_RSHIFT:
14804436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
14814436Sstephh 		    arrowp, try, &lval))
14820Sstevel@tonic-gate 			return (0);
14834436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
14844436Sstephh 		    arrowp, try, &rval))
14850Sstevel@tonic-gate 			return (0);
14860Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
14870Sstevel@tonic-gate 			return (0);
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 		valuep->t = UINT64;
14900Sstevel@tonic-gate 		valuep->v = (lval.v >> rval.v);
14910Sstevel@tonic-gate 		return (1);
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	case T_CONDIF: {
14940Sstevel@tonic-gate 		struct node *retnp;
14950Sstevel@tonic-gate 		int dotrue = 0;
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate 		/*
14980Sstevel@tonic-gate 		 * evaluate
14990Sstevel@tonic-gate 		 *	expression ? stmtA [ : stmtB ]
15000Sstevel@tonic-gate 		 *
15010Sstevel@tonic-gate 		 * first see if expression is true or false, then determine
15020Sstevel@tonic-gate 		 * if stmtA (or stmtB, if it exists) should be evaluated.
15030Sstevel@tonic-gate 		 *
15040Sstevel@tonic-gate 		 * "dotrue = 1" means stmtA should be evaluated.
15050Sstevel@tonic-gate 		 */
15065204Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
15075204Sstephh 		    arrowp, try, &lval))
15085204Sstephh 			return (0);
15095204Sstephh 
15105204Sstephh 		if (lval.t != UNDEFINED && lval.v != 0)
15110Sstevel@tonic-gate 			dotrue = 1;
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 		ASSERT(np->u.expr.right != NULL);
15140Sstevel@tonic-gate 		if (np->u.expr.right->t == T_CONDELSE) {
15150Sstevel@tonic-gate 			if (dotrue)
15160Sstevel@tonic-gate 				retnp = np->u.expr.right->u.expr.left;
15170Sstevel@tonic-gate 			else
15180Sstevel@tonic-gate 				retnp = np->u.expr.right->u.expr.right;
15190Sstevel@tonic-gate 		} else {
15200Sstevel@tonic-gate 			/* no ELSE clause */
15210Sstevel@tonic-gate 			if (dotrue)
15220Sstevel@tonic-gate 				retnp = np->u.expr.right;
15230Sstevel@tonic-gate 			else {
15244436Sstephh 				outfl(O_DIE, np->file, np->line,
15254436Sstephh 				    "eval_expr: missing condelse");
15260Sstevel@tonic-gate 			}
15270Sstevel@tonic-gate 		}
15280Sstevel@tonic-gate 
15294436Sstephh 		if (!eval_expr(retnp, ex, events, globals, croot,
15304436Sstephh 		    arrowp, try, valuep))
15310Sstevel@tonic-gate 			return (0);
15320Sstevel@tonic-gate 		return (1);
15330Sstevel@tonic-gate 	}
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 	case T_CONDELSE:
15360Sstevel@tonic-gate 		/*
15370Sstevel@tonic-gate 		 * shouldn't get here, since T_CONDELSE is supposed to be
15380Sstevel@tonic-gate 		 * evaluated as part of T_CONDIF
15390Sstevel@tonic-gate 		 */
15400Sstevel@tonic-gate 		out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s",
15410Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
15424436Sstephh 		/*NOTREACHED*/
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 	case T_NE:
15454436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
15464436Sstephh 		    arrowp, try, &lval))
15474436Sstephh 			return (0);
15484436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
15494436Sstephh 		    arrowp, try, &rval))
15500Sstevel@tonic-gate 			return (0);
15514436Sstephh 		if (rval.t == UINT64 || lval.t == UINT64) {
15524436Sstephh 			if (check_expr_args(&lval, &rval, UINT64, np))
15534436Sstephh 				return (0);
15544436Sstephh 		} else {
15554436Sstephh 			if (check_expr_args(&lval, &rval, UNDEFINED, np))
15564436Sstephh 				return (0);
15574436Sstephh 		}
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 		valuep->t = UINT64;
15600Sstevel@tonic-gate 		valuep->v = (lval.v != rval.v);
15610Sstevel@tonic-gate 		return (1);
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 	case T_LIST:
15640Sstevel@tonic-gate 	case T_AND:
15654436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
15664436Sstephh 		    arrowp, try, valuep)) {
15673159Sstephh 			/*
15683159Sstephh 			 * if lhs is unknown, still check rhs. If that
15695204Sstephh 			 * is false we can return false irrespective of lhs
15703159Sstephh 			 */
15715204Sstephh 			if (!try) {
15725204Sstephh 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
15735204Sstephh 				return (0);
15745204Sstephh 			}
15754436Sstephh 			if (!eval_expr(np->u.expr.right, ex, events, globals,
15764436Sstephh 			    croot, arrowp, try, valuep)) {
15774436Sstephh 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
15783159Sstephh 				return (0);
15794436Sstephh 			}
15804436Sstephh 			if (valuep->v != 0) {
15814436Sstephh 				np->u.expr.temp = EXPR_TEMP_LHS_UNK;
15823159Sstephh 				return (0);
15834436Sstephh 			}
15843159Sstephh 		}
15850Sstevel@tonic-gate 		if (valuep->v == 0) {
15860Sstevel@tonic-gate 			valuep->t = UINT64;
15870Sstevel@tonic-gate 			return (1);
15880Sstevel@tonic-gate 		}
15894436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
15904436Sstephh 		    arrowp, try, valuep)) {
15914436Sstephh 			np->u.expr.temp = EXPR_TEMP_RHS_UNK;
15920Sstevel@tonic-gate 			return (0);
15934436Sstephh 		}
15940Sstevel@tonic-gate 		valuep->t = UINT64;
15950Sstevel@tonic-gate 		valuep->v = valuep->v == 0 ? 0 : 1;
15960Sstevel@tonic-gate 		return (1);
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	case T_OR:
15994436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
16004436Sstephh 		    arrowp, try, valuep)) {
16013159Sstephh 			/*
16023159Sstephh 			 * if lhs is unknown, still check rhs. If that
16035204Sstephh 			 * is true we can return true irrespective of lhs
16043159Sstephh 			 */
16055204Sstephh 			if (!try) {
16065204Sstephh 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
16075204Sstephh 				return (0);
16085204Sstephh 			}
16094436Sstephh 			if (!eval_expr(np->u.expr.right, ex, events, globals,
16104436Sstephh 			    croot, arrowp, try, valuep)) {
16114436Sstephh 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
16123159Sstephh 				return (0);
16134436Sstephh 			}
16144436Sstephh 			if (valuep->v == 0) {
16154436Sstephh 				np->u.expr.temp = EXPR_TEMP_LHS_UNK;
16163159Sstephh 				return (0);
16174436Sstephh 			}
16183159Sstephh 		}
16190Sstevel@tonic-gate 		if (valuep->v != 0) {
16200Sstevel@tonic-gate 			valuep->t = UINT64;
16210Sstevel@tonic-gate 			valuep->v = 1;
16220Sstevel@tonic-gate 			return (1);
16230Sstevel@tonic-gate 		}
16244436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
16254436Sstephh 		    arrowp, try, valuep)) {
16264436Sstephh 			np->u.expr.temp = EXPR_TEMP_RHS_UNK;
16270Sstevel@tonic-gate 			return (0);
16284436Sstephh 		}
16290Sstevel@tonic-gate 		valuep->t = UINT64;
16300Sstevel@tonic-gate 		valuep->v = valuep->v == 0 ? 0 : 1;
16310Sstevel@tonic-gate 		return (1);
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	case T_NOT:
16344436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
16354436Sstephh 		    arrowp, try, valuep))
16360Sstevel@tonic-gate 			return (0);
16370Sstevel@tonic-gate 		valuep->t = UINT64;
16380Sstevel@tonic-gate 		valuep->v = ! valuep->v;
16390Sstevel@tonic-gate 		return (1);
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	case T_ADD:
16424436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
16434436Sstephh 		    arrowp, try, &lval))
16440Sstevel@tonic-gate 			return (0);
16454436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
16464436Sstephh 		    arrowp, try, &rval))
16470Sstevel@tonic-gate 			return (0);
16480Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
16490Sstevel@tonic-gate 			return (0);
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 		valuep->t = lval.t;
16520Sstevel@tonic-gate 		valuep->v = lval.v + rval.v;
16530Sstevel@tonic-gate 		return (1);
16540Sstevel@tonic-gate 
16550Sstevel@tonic-gate 	case T_SUB:
16564436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
16574436Sstephh 		    arrowp, try, &lval))
16580Sstevel@tonic-gate 			return (0);
16594436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
16604436Sstephh 		    arrowp, try, &rval))
16610Sstevel@tonic-gate 			return (0);
16620Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
16630Sstevel@tonic-gate 			return (0);
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate 		/* since valuep is unsigned, return false if lval.v < rval.v */
16660Sstevel@tonic-gate 		if (lval.v < rval.v) {
16674436Sstephh 			outfl(O_DIE, np->file, np->line,
16684436Sstephh 			    "eval_expr: T_SUB result is out of range");
16690Sstevel@tonic-gate 		}
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 		valuep->t = lval.t;
16720Sstevel@tonic-gate 		valuep->v = lval.v - rval.v;
16730Sstevel@tonic-gate 		return (1);
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 	case T_MUL:
16764436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
16774436Sstephh 		    arrowp, try, &lval))
16780Sstevel@tonic-gate 			return (0);
16794436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
16804436Sstephh 		    arrowp, try, &rval))
16810Sstevel@tonic-gate 			return (0);
16820Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
16830Sstevel@tonic-gate 			return (0);
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 		valuep->t = lval.t;
16860Sstevel@tonic-gate 		valuep->v = lval.v * rval.v;
16870Sstevel@tonic-gate 		return (1);
16880Sstevel@tonic-gate 
16890Sstevel@tonic-gate 	case T_DIV:
16904436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
16914436Sstephh 		    arrowp, try, &lval))
16920Sstevel@tonic-gate 			return (0);
16934436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
16944436Sstephh 		    arrowp, try, &rval))
16950Sstevel@tonic-gate 			return (0);
16960Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
16970Sstevel@tonic-gate 			return (0);
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 		/* return false if dividing by zero */
17000Sstevel@tonic-gate 		if (rval.v == 0) {
17014436Sstephh 			outfl(O_DIE, np->file, np->line,
17024436Sstephh 			    "eval_expr: T_DIV division by zero");
17030Sstevel@tonic-gate 		}
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 		valuep->t = lval.t;
17060Sstevel@tonic-gate 		valuep->v = lval.v / rval.v;
17070Sstevel@tonic-gate 		return (1);
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate 	case T_MOD:
17104436Sstephh 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
17114436Sstephh 		    arrowp, try, &lval))
17120Sstevel@tonic-gate 			return (0);
17134436Sstephh 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
17144436Sstephh 		    arrowp, try, &rval))
17150Sstevel@tonic-gate 			return (0);
17160Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
17170Sstevel@tonic-gate 			return (0);
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 		/* return false if dividing by zero */
17200Sstevel@tonic-gate 		if (rval.v == 0) {
17214436Sstephh 			outfl(O_DIE, np->file, np->line,
17224436Sstephh 			    "eval_expr: T_MOD division by zero");
17230Sstevel@tonic-gate 		}
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 		valuep->t = lval.t;
17260Sstevel@tonic-gate 		valuep->v = lval.v % rval.v;
17270Sstevel@tonic-gate 		return (1);
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 	case T_NAME:
17300Sstevel@tonic-gate 		if (try) {
17310Sstevel@tonic-gate 			struct iterinfo *iterinfop;
17324436Sstephh 			struct node *np1, *np2;
17334436Sstephh 			int i, gotmatch = 0;
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate 			/*
17364436Sstephh 			 * Check if we have an exact match of the nonwildcarded
17374436Sstephh 			 * path in oldepname - if so we can just use the
17384436Sstephh 			 * full wildcarded path in epname.
17390Sstevel@tonic-gate 			 */
17404436Sstephh 			for (i = 0; i < 1; i++) {
17414436Sstephh 				for (np1 = np,
17424436Sstephh 				    np2 = events[i]->u.event.oldepname;
17434436Sstephh 				    np1 != NULL && np2 != NULL;
17444436Sstephh 				    np1 = np1->u.name.next,
17454436Sstephh 				    np2 = np2->u.name.next) {
17464436Sstephh 					if (strcmp(np1->u.name.s,
17474436Sstephh 					    np2->u.name.s) != 0)
17484436Sstephh 						break;
17494436Sstephh 					if (np1->u.name.child->t !=
17504436Sstephh 					    np2->u.name.child->t)
17514436Sstephh 						break;
17524436Sstephh 					if (np1->u.name.child->t == T_NUM &&
17534436Sstephh 					    np1->u.name.child->u.ull !=
17544436Sstephh 					    np2->u.name.child->u.ull)
17554436Sstephh 						break;
17564436Sstephh 					if (np1->u.name.child->t == T_NAME &&
17574436Sstephh 					    strcmp(np1->u.name.child->u.name.s,
17584436Sstephh 					    np2->u.name.child->u.name.s) != 0)
17594436Sstephh 						break;
17604436Sstephh 					gotmatch++;
17614436Sstephh 				}
17624436Sstephh 				if (np1 == NULL && np2 == NULL) {
17634436Sstephh 					valuep->t = NODEPTR;
17644436Sstephh 					valuep->v = (uintptr_t)
17654436Sstephh 					    events[i]->u.event.epname;
17664436Sstephh 					return (1);
17674436Sstephh 				}
17680Sstevel@tonic-gate 			}
17694436Sstephh 			if (!gotmatch) {
17704436Sstephh 				/*
17714436Sstephh 				 * we're not wildcarding. However at
17724436Sstephh 				 * itree_create() time, we can also expand
17734436Sstephh 				 * simple iterators - so check for those.
17744436Sstephh 				 */
17754436Sstephh 				iterinfop = lut_lookup(ex, (void *)np->u.name.s,
17764436Sstephh 				    NULL);
17774436Sstephh 				if (iterinfop != NULL) {
17784436Sstephh 					valuep->t = UINT64;
17794436Sstephh 					valuep->v =
17804436Sstephh 					    (unsigned long long)iterinfop->num;
17814436Sstephh 					return (1);
17824436Sstephh 				}
17834436Sstephh 			}
17844436Sstephh 			/*
17854436Sstephh 			 * For anything else we'll have to wait for eval_dup().
17864436Sstephh 			 */
17870Sstevel@tonic-gate 			return (0);
17880Sstevel@tonic-gate 		}
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate 		/* return address of struct node */
17910Sstevel@tonic-gate 		valuep->t = NODEPTR;
17921717Swesolows 		valuep->v = (uintptr_t)np;
17930Sstevel@tonic-gate 		return (1);
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 	case T_QUOTE:
17960Sstevel@tonic-gate 		valuep->t = STRING;
17971717Swesolows 		valuep->v = (uintptr_t)np->u.quote.s;
17980Sstevel@tonic-gate 		return (1);
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 	case T_FUNC:
18014436Sstephh 		return (eval_func(np, ex, events, np->u.func.arglist,
18024436Sstephh 		    globals, croot, arrowp, try, valuep));
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate 	case T_NUM:
18057197Sstephh 	case T_TIMEVAL:
18060Sstevel@tonic-gate 		valuep->t = UINT64;
18070Sstevel@tonic-gate 		valuep->v = np->u.ull;
18080Sstevel@tonic-gate 		return (1);
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate 	default:
18110Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
18120Sstevel@tonic-gate 		    "eval_expr: unexpected node type: %s",
18130Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
18140Sstevel@tonic-gate 	}
18150Sstevel@tonic-gate 	/*NOTREACHED*/
18161717Swesolows 	return (0);
18170Sstevel@tonic-gate }
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate /*
18200Sstevel@tonic-gate  * eval_fru() and eval_asru() don't do much, but are called from a number
18210Sstevel@tonic-gate  * of places.
18220Sstevel@tonic-gate  */
18234436Sstephh static struct node *
18240Sstevel@tonic-gate eval_fru(struct node *np)
18250Sstevel@tonic-gate {
18260Sstevel@tonic-gate 	ASSERT(np->t == T_NAME);
18270Sstevel@tonic-gate 	return (np);
18280Sstevel@tonic-gate }
18290Sstevel@tonic-gate 
18304436Sstephh static struct node *
18310Sstevel@tonic-gate eval_asru(struct node *np)
18320Sstevel@tonic-gate {
18330Sstevel@tonic-gate 	ASSERT(np->t == T_NAME);
18340Sstevel@tonic-gate 	return (np);
18350Sstevel@tonic-gate }
1836