xref: /illumos-gate/usr/src/cmd/fm/modules/common/eversholt/eval.c (revision 89a7715a55deca73d03076f5c24463717f0aaa91)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * eval.c -- constraint evaluation module
27  *
28  * this module evaluates constraints.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include "alloc.h"
38 #include "out.h"
39 #include "stable.h"
40 #include "literals.h"
41 #include "lut.h"
42 #include "tree.h"
43 #include "ptree.h"
44 #include "itree.h"
45 #include "ipath.h"
46 #include "eval.h"
47 #include "config.h"
48 #include "platform.h"
49 #include "fme.h"
50 #include "stats.h"
51 
52 static struct node *eval_dup(struct node *np, struct lut *ex,
53     struct node *events[]);
54 static int check_expr_args(struct evalue *lp, struct evalue *rp,
55     enum datatype dtype, struct node *np);
56 static struct node *eval_fru(struct node *np);
57 static struct node *eval_asru(struct node *np);
58 
59 /*
60  * begins_with -- return true if rhs path begins with everything in lhs path
61  */
62 static int
63 begins_with(struct node *lhs, struct node *rhs, struct lut *ex)
64 {
65 	int lnum;
66 	int rnum;
67 	struct iterinfo *iterinfop;
68 
69 	if (lhs == NULL)
70 		return (1);	/* yep -- it all matched */
71 
72 	if (rhs == NULL)
73 		return (0);	/* nope, ran out of rhs first */
74 
75 	ASSERTeq(lhs->t, T_NAME, ptree_nodetype2str);
76 	ASSERTeq(rhs->t, T_NAME, ptree_nodetype2str);
77 
78 	if (lhs->u.name.s != rhs->u.name.s)
79 		return (0);	/* nope, different component names */
80 
81 	if (lhs->u.name.child && lhs->u.name.child->t == T_NUM) {
82 		lnum = (int)lhs->u.name.child->u.ull;
83 	} else if (lhs->u.name.child && lhs->u.name.child->t == T_NAME) {
84 		iterinfop = lut_lookup(ex, (void *)lhs->u.name.child->u.name.s,
85 		    NULL);
86 		if (iterinfop != NULL)
87 			lnum = iterinfop->num;
88 		else
89 			out(O_DIE, "begins_with: unexpected lhs child");
90 	} else {
91 		out(O_DIE, "begins_with: unexpected lhs child");
92 	}
93 
94 	if (rhs->u.name.child && rhs->u.name.child->t == T_NUM) {
95 		rnum = (int)rhs->u.name.child->u.ull;
96 	} else if (rhs->u.name.child && rhs->u.name.child->t == T_NAME) {
97 		iterinfop = lut_lookup(ex, (void *)rhs->u.name.child->u.name.s,
98 		    NULL);
99 		if (iterinfop != NULL)
100 			rnum = iterinfop->num;
101 		else
102 			out(O_DIE, "begins_with: unexpected rhs child");
103 	} else {
104 		out(O_DIE, "begins_with: unexpected rhs child");
105 	}
106 
107 	if (lnum != rnum)
108 		return (0);	/* nope, instance numbers were different */
109 
110 	return (begins_with(lhs->u.name.next, rhs->u.name.next, ex));
111 }
112 
113 /*
114  * eval_getname - used by eval_func to evaluate a name, preferably without using
115  * eval_dup (but if it does have to use eval_dup then the *dupedp flag is set).
116  */
117 static struct node *
118 eval_getname(struct node *funcnp, struct lut *ex, struct node *events[],
119     struct node *np, struct lut **globals,
120     struct config *croot, struct arrow *arrowp, int try, int *dupedp)
121 {
122 	struct node *nodep;
123 	const char *funcname = funcnp->u.func.s;
124 	struct evalue val;
125 
126 	if (np->t == T_NAME)
127 		nodep = np;
128 	else if (np->u.func.s == L_fru)
129 		nodep = eval_fru(np->u.func.arglist);
130 	else if (np->u.func.s == L_asru)
131 		nodep = eval_asru(np->u.func.arglist);
132 	else
133 		out(O_DIE, "%s: unexpected type: %s",
134 		    funcname, ptree_nodetype2str(np->t));
135 	if (try) {
136 		if (eval_expr(nodep, ex, events, globals, croot,
137 		    arrowp, try, &val) && val.t == NODEPTR)
138 			nodep = (struct node *)(uintptr_t)val.v;
139 		else {
140 			*dupedp = 1;
141 			nodep = eval_dup(nodep, ex, events);
142 		}
143 	}
144 	return (nodep);
145 }
146 
147 /*
148  * evaluate a variety of functions and place result in valuep.  return 1 if
149  * function evaluation was successful; 0 if otherwise (e.g., the case of an
150  * invalid argument to the function)
151  */
152 /*ARGSUSED*/
153 static int
154 eval_func(struct node *funcnp, struct lut *ex, struct node *events[],
155     struct node *np, struct lut **globals,
156     struct config *croot, struct arrow *arrowp, int try, struct evalue *valuep)
157 {
158 	const char *funcname = funcnp->u.func.s;
159 	int duped_lhs = 0, duped_rhs = 0, duped = 0;
160 	struct node *lhs;
161 	struct node *rhs;
162 	struct config *cp;
163 	struct node *nodep;
164 	char *path;
165 	struct evalue val;
166 
167 	if (funcname == L_within) {
168 		/* within()'s are not really constraints -- always true */
169 		valuep->t = UINT64;
170 		valuep->v = 1;
171 		return (1);
172 	} else if (funcname == L_is_under) {
173 		lhs = eval_getname(funcnp, ex, events, np->u.expr.left, globals,
174 		    croot, arrowp, try, &duped_lhs);
175 		rhs = eval_getname(funcnp, ex, events, np->u.expr.right,
176 		    globals, croot, arrowp, try, &duped_rhs);
177 
178 		valuep->t = UINT64;
179 		valuep->v = begins_with(lhs, rhs, ex);
180 		out(O_ALTFP|O_VERB2|O_NONL, "eval_func:is_under(");
181 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, lhs);
182 		out(O_ALTFP|O_VERB2|O_NONL, ",");
183 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, rhs);
184 		out(O_ALTFP|O_VERB2|O_NONL, ") returned %d", (int)valuep->v);
185 
186 		if (duped_lhs)
187 			tree_free(lhs);
188 		if (duped_rhs)
189 			tree_free(rhs);
190 		return (1);
191 	} else if (funcname == L_confprop || funcname == L_confprop_defined) {
192 		const char *s;
193 
194 		/* for now s will point to a quote [see addconfigprop()] */
195 		ASSERT(np->u.expr.right->t == T_QUOTE);
196 
197 		nodep = eval_getname(funcnp, ex, events, np->u.expr.left,
198 		    globals, croot, arrowp, try, &duped);
199 		if (nodep->u.name.last->u.name.cp != NULL) {
200 			cp = nodep->u.name.last->u.name.cp;
201 		} else {
202 			path = ipath2str(NULL, ipath(nodep));
203 			cp = config_lookup(croot, path, 0);
204 			FREE((void *)path);
205 		}
206 		if (cp == NULL) {
207 			if (funcname == L_confprop) {
208 				out(O_ALTFP|O_VERB3, "%s: path ", funcname);
209 				ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep);
210 				out(O_ALTFP|O_VERB3, " not found");
211 				valuep->v = (uintptr_t)stable("");
212 				valuep->t = STRING;
213 				if (duped)
214 					tree_free(nodep);
215 				return (1);
216 			} else {
217 				valuep->v = 0;
218 				valuep->t = UINT64;
219 				if (duped)
220 					tree_free(nodep);
221 				return (1);
222 			}
223 		}
224 		s = config_getprop(cp, np->u.expr.right->u.quote.s);
225 		if (s == NULL && strcmp(np->u.expr.right->u.quote.s,
226 		    "class-code") == 0)
227 			s = config_getprop(cp, "CLASS-CODE");
228 		if (s == NULL) {
229 			if (funcname == L_confprop) {
230 				out(O_ALTFP|O_VERB3|O_NONL,
231 				    "%s: \"%s\" not found for path ",
232 				    funcname, np->u.expr.right->u.quote.s);
233 				ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep);
234 				valuep->v = (uintptr_t)stable("");
235 				valuep->t = STRING;
236 				if (duped)
237 					tree_free(nodep);
238 				return (1);
239 			} else {
240 				valuep->v = 0;
241 				valuep->t = UINT64;
242 				if (duped)
243 					tree_free(nodep);
244 				return (1);
245 			}
246 		}
247 
248 		if (funcname == L_confprop) {
249 			valuep->v = (uintptr_t)stable(s);
250 			valuep->t = STRING;
251 			out(O_ALTFP|O_VERB3|O_NONL, "  %s(\"", funcname);
252 			ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep);
253 			out(O_ALTFP|O_VERB3|O_NONL,
254 			    "\", \"%s\") = \"%s\"  ",
255 			    np->u.expr.right->u.quote.s,
256 			    (char *)(uintptr_t)valuep->v);
257 		} else {
258 			valuep->v = 1;
259 			valuep->t = UINT64;
260 		}
261 		if (duped)
262 			tree_free(nodep);
263 		return (1);
264 	} else if (funcname == L_is_connected) {
265 		const char *connstrings[] = { "connected", "CONNECTED", NULL };
266 		struct config *cp[2];
267 		const char *matchthis[2], *s;
268 		char *nameslist, *w;
269 		int i, j;
270 
271 		lhs = eval_getname(funcnp, ex, events, np->u.expr.left, globals,
272 		    croot, arrowp, try, &duped_lhs);
273 		rhs = eval_getname(funcnp, ex, events, np->u.expr.right,
274 		    globals, croot, arrowp, try, &duped_rhs);
275 		path = ipath2str(NULL, ipath(lhs));
276 		matchthis[1] = stable(path);
277 		if (lhs->u.name.last->u.name.cp != NULL)
278 			cp[0] = lhs->u.name.last->u.name.cp;
279 		else
280 			cp[0] = config_lookup(croot, path, 0);
281 		FREE((void *)path);
282 		path = ipath2str(NULL, ipath(rhs));
283 		matchthis[0] = stable(path);
284 		if (rhs->u.name.last->u.name.cp != NULL)
285 			cp[1] = rhs->u.name.last->u.name.cp;
286 		else
287 			cp[1] = config_lookup(croot, path, 0);
288 		FREE((void *)path);
289 		if (duped_lhs)
290 			tree_free(lhs);
291 		if (duped_rhs)
292 			tree_free(rhs);
293 
294 		valuep->t = UINT64;
295 		valuep->v = 0;
296 		if (cp[0] == NULL || cp[1] == NULL)
297 			return (1);
298 
299 		/* to thine self always be connected */
300 		if (cp[0] == cp[1]) {
301 			valuep->v = 1;
302 			return (1);
303 		}
304 
305 		/*
306 		 * Extract "connected" property from each cp. Search this
307 		 * property for the name associated with the other cp[].
308 		 */
309 		for (i = 0; i < 2 && valuep->v == 0; i++) {
310 			for (j = 0; connstrings[j] != NULL && valuep->v == 0;
311 			    j++) {
312 				s = config_getprop(cp[i],
313 				    stable(connstrings[j]));
314 				if (s != NULL) {
315 					nameslist = STRDUP(s);
316 					w = strtok(nameslist, " ,");
317 					while (w != NULL) {
318 						if (stable(w) == matchthis[i]) {
319 							valuep->v = 1;
320 							break;
321 						}
322 						w = strtok(NULL, " ,");
323 					}
324 					FREE(nameslist);
325 				}
326 			}
327 		}
328 		return (1);
329 	} else if (funcname == L_is_type) {
330 		const char *typestrings[] = { "type", "TYPE", NULL };
331 		const char *s;
332 		int i;
333 
334 		nodep = eval_getname(funcnp, ex, events, np, globals,
335 		    croot, arrowp, try, &duped);
336 		if (nodep->u.name.last->u.name.cp != NULL) {
337 			cp = nodep->u.name.last->u.name.cp;
338 		} else {
339 			path = ipath2str(NULL, ipath(nodep));
340 			cp = config_lookup(croot, path, 0);
341 			FREE((void *)path);
342 		}
343 		if (duped)
344 			tree_free(nodep);
345 
346 		valuep->t = STRING;
347 		valuep->v = (uintptr_t)stable("");
348 		if (cp == NULL)
349 			return (1);
350 		for (i = 0; typestrings[i] != NULL; i++) {
351 			s = config_getprop(cp, stable(typestrings[i]));
352 			if (s != NULL) {
353 				valuep->v = (uintptr_t)stable(s);
354 				break;
355 			}
356 		}
357 		return (1);
358 	} else if (funcname == L_is_on) {
359 		const char *onstrings[] = { "on", "ON", NULL };
360 		const char *truestrings[] = { "yes", "YES", "y", "Y",
361 				    "true", "TRUE", "t", "T", "1", NULL };
362 		const char *s;
363 		int i, j;
364 
365 		nodep = eval_getname(funcnp, ex, events, np, globals,
366 		    croot, arrowp, try, &duped);
367 		if (nodep->u.name.last->u.name.cp != NULL) {
368 			cp = nodep->u.name.last->u.name.cp;
369 		} else {
370 			path = ipath2str(NULL, ipath(nodep));
371 			cp = config_lookup(croot, path, 0);
372 			FREE((void *)path);
373 		}
374 		if (duped)
375 			tree_free(nodep);
376 
377 		valuep->t = UINT64;
378 		valuep->v = 0;
379 		if (cp == NULL)
380 			return (1);
381 		for (i = 0; onstrings[i] != NULL; i++) {
382 			s = config_getprop(cp, stable(onstrings[i]));
383 			if (s != NULL) {
384 				s = stable(s);
385 				for (j = 0; truestrings[j] != NULL; j++) {
386 					if (s == stable(truestrings[j])) {
387 						valuep->v = 1;
388 						return (1);
389 					}
390 				}
391 			}
392 		}
393 		return (1);
394 	} else if (funcname == L_is_present) {
395 		nodep = eval_getname(funcnp, ex, events, np, globals,
396 		    croot, arrowp, try, &duped);
397 		if (nodep->u.name.last->u.name.cp != NULL) {
398 			cp = nodep->u.name.last->u.name.cp;
399 		} else {
400 			path = ipath2str(NULL, ipath(nodep));
401 			cp = config_lookup(croot, path, 0);
402 			FREE((void *)path);
403 		}
404 		if (duped)
405 			tree_free(nodep);
406 
407 		valuep->t = UINT64;
408 		valuep->v = 0;
409 		if (cp != NULL)
410 			valuep->v = 1;
411 		return (1);
412 	} else if (funcname == L_count) {
413 		struct stats *statp;
414 		struct istat_entry ent;
415 
416 		ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t));
417 
418 		nodep = np->u.event.epname;
419 		if (try) {
420 			if (eval_expr(nodep, ex, events, globals,
421 			    croot, arrowp, try, &val) && val.t == NODEPTR)
422 				nodep = (struct node *)(uintptr_t)val.v;
423 			else {
424 				duped = 1;
425 				nodep = eval_dup(nodep, ex, events);
426 			}
427 		}
428 		ent.ename = np->u.event.ename->u.name.s;
429 		ent.ipath = ipath(nodep);
430 		valuep->t = UINT64;
431 		if ((statp = (struct stats *)
432 		    lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL)
433 			valuep->v = 0;
434 		else
435 			valuep->v = stats_counter_value(statp);
436 		if (duped)
437 			tree_free(nodep);
438 		return (1);
439 	} else if (funcname == L_envprop) {
440 		outfl(O_DIE, np->file, np->line,
441 		    "eval_func: %s not yet supported", funcname);
442 	}
443 
444 	if (try)
445 		return (0);
446 
447 	if (funcname == L_fru) {
448 		valuep->t = NODEPTR;
449 		valuep->v = (uintptr_t)eval_fru(np);
450 		return (1);
451 	} else if (funcname == L_asru) {
452 		valuep->t = NODEPTR;
453 		valuep->v = (uintptr_t)eval_asru(np);
454 		return (1);
455 	} else if (funcname == L_defined) {
456 		ASSERTeq(np->t, T_GLOBID, ptree_nodetype2str);
457 		valuep->t = UINT64;
458 		valuep->v = (lut_lookup(*globals,
459 		    (void *)np->u.globid.s, NULL) != NULL);
460 		return (1);
461 	} else if (funcname == L_call) {
462 		return (! platform_call(np, globals, croot, arrowp, valuep));
463 	} else if (funcname == L_payloadprop) {
464 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
465 		    "payloadprop(\"%s\") ", np->u.quote.s);
466 
467 		if (arrowp->head->myevent->count == 0) {
468 			/*
469 			 * Haven't seen this ereport yet, so must defer
470 			 */
471 			out(O_ALTFP|O_VERB2, "ereport not yet seen - defer.");
472 			return (0);
473 		} else if (platform_payloadprop(np, valuep)) {
474 			/* platform_payloadprop() returned false */
475 			out(O_ALTFP|O_VERB, "not found.");
476 			valuep->t = UNDEFINED;
477 			return (1);
478 		} else {
479 			switch (valuep->t) {
480 			case UINT64:
481 			case NODEPTR:
482 				out(O_ALTFP|O_VERB2, "found: %llu", valuep->v);
483 				break;
484 			case STRING:
485 				out(O_ALTFP|O_VERB2, "found: \"%s\"",
486 				    (char *)(uintptr_t)valuep->v);
487 				break;
488 			default:
489 				out(O_ALTFP|O_VERB2, "found: undefined");
490 				break;
491 			}
492 			return (1);
493 		}
494 	} else if (funcname == L_setpayloadprop) {
495 		struct evalue *payloadvalp;
496 		int alloced = 0;
497 
498 		ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t));
499 		ASSERTinfo(np->u.expr.left->t == T_QUOTE,
500 		    ptree_nodetype2str(np->u.expr.left->t));
501 
502 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
503 		    "setpayloadprop: %s: %s=",
504 		    arrowp->tail->myevent->enode->u.event.ename->u.name.s,
505 		    np->u.expr.left->u.quote.s);
506 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right);
507 
508 		/*
509 		 * allocate a struct evalue to hold the payload property's
510 		 * value, unless we've been here already, in which case we
511 		 * might calculate a different value, but we'll store it
512 		 * in the already-allocated struct evalue.
513 		 */
514 		if ((payloadvalp = (struct evalue *)lut_lookup(
515 		    arrowp->tail->myevent->payloadprops,
516 		    (void *)np->u.expr.left->u.quote.s, NULL)) == NULL) {
517 			payloadvalp = MALLOC(sizeof (*payloadvalp));
518 			alloced = 1;
519 		}
520 
521 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
522 		    arrowp, try, payloadvalp)) {
523 			out(O_ALTFP|O_VERB2, " (cannot eval)");
524 			if (alloced)
525 				FREE(payloadvalp);
526 			return (0);
527 		} else {
528 			if (payloadvalp->t == UNDEFINED) {
529 				/* function is always true */
530 				out(O_ALTFP|O_VERB2, " (undefined)");
531 				valuep->t = UINT64;
532 				valuep->v = 1;
533 				return (1);
534 			}
535 			if (payloadvalp->t == UINT64)
536 				out(O_ALTFP|O_VERB2,
537 				    " (%llu)", payloadvalp->v);
538 			else
539 				out(O_ALTFP|O_VERB2, " (\"%s\")",
540 				    (char *)(uintptr_t)payloadvalp->v);
541 		}
542 
543 		/* add to table of payload properties for current problem */
544 		arrowp->tail->myevent->payloadprops =
545 		    lut_add(arrowp->tail->myevent->payloadprops,
546 		    (void *)np->u.expr.left->u.quote.s,
547 		    (void *)payloadvalp, NULL);
548 
549 		/* function is always true */
550 		valuep->t = UINT64;
551 		valuep->v = 1;
552 		return (1);
553 	} else if (funcname == L_payloadprop_defined) {
554 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
555 		    "payloadprop_defined(\"%s\") ", np->u.quote.s);
556 
557 		if (arrowp->head->myevent->count == 0) {
558 			/*
559 			 * Haven't seen this ereport yet, so must defer
560 			 */
561 			out(O_ALTFP|O_VERB2, "ereport not yet seen - defer.");
562 			return (0);
563 		} else if (platform_payloadprop(np, NULL)) {
564 			/* platform_payloadprop() returned false */
565 			valuep->v = 0;
566 			out(O_ALTFP|O_VERB2, "not found.");
567 		} else {
568 			valuep->v = 1;
569 			out(O_ALTFP|O_VERB2, "found.");
570 		}
571 		valuep->t = UINT64;
572 		return (1);
573 	} else if (funcname == L_payloadprop_contains) {
574 		int nvals;
575 		struct evalue *vals;
576 		struct evalue cmpval;
577 
578 		ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t));
579 		ASSERTinfo(np->u.expr.left->t == T_QUOTE,
580 		    ptree_nodetype2str(np->u.expr.left->t));
581 
582 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
583 		    "payloadprop_contains(\"%s\", ",
584 		    np->u.expr.left->u.quote.s);
585 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right);
586 		out(O_ALTFP|O_VERB2|O_NONL, ") ");
587 
588 		/* evaluate the expression we're comparing against */
589 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
590 		    arrowp, try, &cmpval)) {
591 			out(O_ALTFP|O_VERB2|O_NONL,
592 			    "(cannot eval) ");
593 			return (0);
594 		} else {
595 			switch (cmpval.t) {
596 			case UNDEFINED:
597 				out(O_ALTFP|O_VERB2, "(undefined type)");
598 				break;
599 
600 			case UINT64:
601 				out(O_ALTFP|O_VERB2,
602 				    "(%llu) ", cmpval.v);
603 				break;
604 
605 			case STRING:
606 				out(O_ALTFP|O_VERB2,
607 				    "(\"%s\") ", (char *)(uintptr_t)cmpval.v);
608 				break;
609 
610 			case NODEPTR:
611 				out(O_ALTFP|O_VERB2|O_NONL, "(");
612 				ptree_name_iter(O_ALTFP|O_VERB2|O_NONL,
613 				    (struct node *)(uintptr_t)(cmpval.v));
614 				out(O_ALTFP|O_VERB2, ") ");
615 				break;
616 			}
617 		}
618 
619 		/* get the payload values and check for a match */
620 		vals = platform_payloadprop_values(np->u.expr.left->u.quote.s,
621 		    &nvals);
622 		valuep->t = UINT64;
623 		valuep->v = 0;
624 		if (arrowp->head->myevent->count == 0) {
625 			/*
626 			 * Haven't seen this ereport yet, so must defer
627 			 */
628 			out(O_ALTFP|O_VERB2, "ereport not yet seen - defer.");
629 			return (0);
630 		} else if (nvals == 0) {
631 			out(O_ALTFP|O_VERB2, "not found.");
632 			return (1);
633 		} else {
634 			struct evalue preval;
635 			int i;
636 
637 			out(O_ALTFP|O_VERB2|O_NONL, "found %d values ", nvals);
638 
639 			for (i = 0; i < nvals; i++) {
640 
641 				preval.t = vals[i].t;
642 				preval.v = vals[i].v;
643 
644 				if (check_expr_args(&vals[i], &cmpval,
645 				    UNDEFINED, np))
646 					continue;
647 
648 				/*
649 				 * If we auto-converted the value to a
650 				 * string, we need to free the
651 				 * original tree value.
652 				 */
653 				if (preval.t == NODEPTR &&
654 				    ((struct node *)(uintptr_t)(preval.v))->t ==
655 				    T_NAME) {
656 					tree_free((struct node *)(uintptr_t)
657 					    preval.v);
658 				}
659 
660 				if (vals[i].v == cmpval.v) {
661 					valuep->v = 1;
662 					break;
663 				}
664 			}
665 
666 			if (valuep->v)
667 				out(O_ALTFP|O_VERB2, "match.");
668 			else
669 				out(O_ALTFP|O_VERB2, "no match.");
670 
671 			for (i = 0; i < nvals; i++) {
672 				if (vals[i].t == NODEPTR) {
673 					tree_free((struct node *)(uintptr_t)
674 					    vals[i].v);
675 					break;
676 				}
677 			}
678 			FREE(vals);
679 		}
680 		return (1);
681 	} else if (funcname == L_confcall) {
682 		return (!platform_confcall(np, globals, croot, arrowp, valuep));
683 	} else
684 		outfl(O_DIE, np->file, np->line,
685 		    "eval_func: unexpected func: %s", funcname);
686 	/*NOTREACHED*/
687 	return (0);
688 }
689 
690 /*
691  * defines for u.expr.temp - these are used for T_OR and T_AND so that if
692  * we worked out that part of the expression was true or false during an
693  * earlier eval_expr, then we don't need to dup that part.
694  */
695 
696 #define	EXPR_TEMP_BOTH_UNK	0
697 #define	EXPR_TEMP_LHS_UNK	1
698 #define	EXPR_TEMP_RHS_UNK	2
699 
700 static struct node *
701 eval_dup(struct node *np, struct lut *ex, struct node *events[])
702 {
703 	struct node *newnp;
704 
705 	if (np == NULL)
706 		return (NULL);
707 
708 	switch (np->t) {
709 	case T_GLOBID:
710 		return (tree_globid(np->u.globid.s, np->file, np->line));
711 
712 	case T_ASSIGN:
713 	case T_CONDIF:
714 	case T_CONDELSE:
715 	case T_NE:
716 	case T_EQ:
717 	case T_LT:
718 	case T_LE:
719 	case T_GT:
720 	case T_GE:
721 	case T_BITAND:
722 	case T_BITOR:
723 	case T_BITXOR:
724 	case T_BITNOT:
725 	case T_LSHIFT:
726 	case T_RSHIFT:
727 	case T_NOT:
728 	case T_ADD:
729 	case T_SUB:
730 	case T_MUL:
731 	case T_DIV:
732 	case T_MOD:
733 		return (tree_expr(np->t,
734 		    eval_dup(np->u.expr.left, ex, events),
735 		    eval_dup(np->u.expr.right, ex, events)));
736 	case T_LIST:
737 	case T_AND:
738 		switch (np->u.expr.temp) {
739 		case EXPR_TEMP_LHS_UNK:
740 			return (eval_dup(np->u.expr.left, ex, events));
741 		case EXPR_TEMP_RHS_UNK:
742 			return (eval_dup(np->u.expr.right, ex, events));
743 		default:
744 			return (tree_expr(np->t,
745 			    eval_dup(np->u.expr.left, ex, events),
746 			    eval_dup(np->u.expr.right, ex, events)));
747 		}
748 
749 	case T_OR:
750 		switch (np->u.expr.temp) {
751 		case EXPR_TEMP_LHS_UNK:
752 			return (eval_dup(np->u.expr.left, ex, events));
753 		case EXPR_TEMP_RHS_UNK:
754 			return (eval_dup(np->u.expr.right, ex, events));
755 		default:
756 			return (tree_expr(T_OR,
757 			    eval_dup(np->u.expr.left, ex, events),
758 			    eval_dup(np->u.expr.right, ex, events)));
759 		}
760 
761 	case T_NAME: {
762 		struct iterinfo *iterinfop;
763 		int got_matchf = 0;
764 		int got_matcht = 0;
765 		struct evalue value;
766 		struct node *np1f, *np2f, *np1t, *np2t, *retp = NULL;
767 		struct node *npstart, *npcont, *npend, *npref, *newnp, *nprest;
768 
769 		/*
770 		 * Check if we already have a match of the nonwildcarded path
771 		 * in oldepname (check both to and from events).
772 		 */
773 		for (np1f = np, np2f = events[0]->u.event.oldepname;
774 		    np1f != NULL && np2f != NULL;
775 		    np1f = np1f->u.name.next, np2f = np2f->u.name.next) {
776 			if (strcmp(np1f->u.name.s, np2f->u.name.s) != 0)
777 				break;
778 			if (np1f->u.name.child->t != np2f->u.name.child->t)
779 				break;
780 			if (np1f->u.name.child->t == T_NUM &&
781 			    np1f->u.name.child->u.ull !=
782 			    np2f->u.name.child->u.ull)
783 				break;
784 			if (np1f->u.name.child->t == T_NAME &&
785 			    strcmp(np1f->u.name.child->u.name.s,
786 			    np2f->u.name.child->u.name.s) != 0)
787 				break;
788 			got_matchf++;
789 		}
790 		for (np1t = np, np2t = events[1]->u.event.oldepname;
791 		    np1t != NULL && np2t != NULL;
792 		    np1t = np1t->u.name.next, np2t = np2t->u.name.next) {
793 			if (strcmp(np1t->u.name.s, np2t->u.name.s) != 0)
794 				break;
795 			if (np1t->u.name.child->t != np2t->u.name.child->t)
796 				break;
797 			if (np1t->u.name.child->t == T_NUM &&
798 			    np1t->u.name.child->u.ull !=
799 			    np2t->u.name.child->u.ull)
800 				break;
801 			if (np1t->u.name.child->t == T_NAME &&
802 			    strcmp(np1t->u.name.child->u.name.s,
803 			    np2t->u.name.child->u.name.s) != 0)
804 				break;
805 			got_matcht++;
806 		}
807 		nprest = np;
808 		if (got_matchf || got_matcht) {
809 			/*
810 			 * so we are wildcarding. Copy ewname in full, plus
811 			 * matching section of oldepname. Use whichever gives
812 			 * the closest match.
813 			 */
814 			if (got_matchf > got_matcht) {
815 				npstart = events[0]->u.event.ewname;
816 				npcont = events[0]->u.event.oldepname;
817 				npend = np2f;
818 				nprest = np1f;
819 			} else {
820 				npstart = events[1]->u.event.ewname;
821 				npcont = events[1]->u.event.oldepname;
822 				npend = np2t;
823 				nprest = np1t;
824 			}
825 			for (npref = npstart; npref != NULL;
826 			    npref = npref->u.name.next) {
827 				newnp = newnode(T_NAME, np->file, np->line);
828 				newnp->u.name.t = npref->u.name.t;
829 				newnp->u.name.s = npref->u.name.s;
830 				newnp->u.name.last = newnp;
831 				newnp->u.name.it = npref->u.name.it;
832 				newnp->u.name.cp = npref->u.name.cp;
833 				newnp->u.name.child =
834 				    newnode(T_NUM, np->file, np->line);
835 				if (eval_expr(npref->u.name.child, ex, events,
836 				    NULL, NULL, NULL, 1, &value) == 0 ||
837 				    value.t != UINT64) {
838 					outfl(O_DIE, np->file, np->line,
839 					    "eval_dup: could not resolve "
840 					    "iterator of %s", np->u.name.s);
841 				}
842 				newnp->u.name.child->u.ull = value.v;
843 				if (retp == NULL) {
844 					retp = newnp;
845 				} else {
846 					retp->u.name.last->u.name.next = newnp;
847 					retp->u.name.last = newnp;
848 				}
849 			}
850 			for (npref = npcont; npref != NULL && npref != npend;
851 			    npref = npref->u.name.next) {
852 				newnp = newnode(T_NAME, np->file, np->line);
853 				newnp->u.name.t = npref->u.name.t;
854 				newnp->u.name.s = npref->u.name.s;
855 				newnp->u.name.last = newnp;
856 				newnp->u.name.it = npref->u.name.it;
857 				newnp->u.name.cp = npref->u.name.cp;
858 				newnp->u.name.child =
859 				    newnode(T_NUM, np->file, np->line);
860 				if (eval_expr(npref->u.name.child, ex, events,
861 				    NULL, NULL, NULL, 1, &value) == 0 ||
862 				    value.t != UINT64) {
863 					outfl(O_DIE, np->file, np->line,
864 					    "eval_dup: could not resolve "
865 					    "iterator of %s", np->u.name.s);
866 				}
867 				newnp->u.name.child->u.ull = value.v;
868 				if (retp == NULL) {
869 					retp = newnp;
870 				} else {
871 					retp->u.name.last->u.name.next = newnp;
872 					retp->u.name.last = newnp;
873 				}
874 			}
875 		} else {
876 			/*
877 			 * not wildcarding - check if explicit iterator
878 			 */
879 			iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
880 			if (iterinfop != NULL) {
881 				/* explicit iterator; not part of pathname */
882 				newnp = newnode(T_NUM, np->file, np->line);
883 				newnp->u.ull = iterinfop->num;
884 				return (newnp);
885 			}
886 		}
887 
888 		/*
889 		 * finally, whether wildcarding or not, we need to copy the
890 		 * remaining part of the path (if any). This must be defined
891 		 * absolutely (no more expansion/wildcarding).
892 		 */
893 		for (npref = nprest; npref != NULL;
894 		    npref = npref->u.name.next) {
895 			newnp = newnode(T_NAME, np->file, np->line);
896 			newnp->u.name.t = npref->u.name.t;
897 			newnp->u.name.s = npref->u.name.s;
898 			newnp->u.name.last = newnp;
899 			newnp->u.name.it = npref->u.name.it;
900 			newnp->u.name.cp = npref->u.name.cp;
901 			newnp->u.name.child =
902 			    newnode(T_NUM, np->file, np->line);
903 			if (eval_expr(npref->u.name.child, ex, events,
904 			    NULL, NULL, NULL, 1, &value) == 0 ||
905 			    value.t != UINT64) {
906 				outfl(O_DIE, np->file, np->line,
907 				    "eval_dup: could not resolve "
908 				    "iterator of %s", np->u.name.s);
909 			}
910 			newnp->u.name.child->u.ull = value.v;
911 			if (retp == NULL) {
912 				retp = newnp;
913 			} else {
914 				retp->u.name.last->u.name.next = newnp;
915 				retp->u.name.last = newnp;
916 			}
917 		}
918 		return (retp);
919 	}
920 
921 	case T_EVENT:
922 		newnp = newnode(T_NAME, np->file, np->line);
923 
924 		newnp->u.name.t = np->u.event.ename->u.name.t;
925 		newnp->u.name.s = np->u.event.ename->u.name.s;
926 		newnp->u.name.it = np->u.event.ename->u.name.it;
927 		newnp->u.name.last = newnp;
928 
929 		return (tree_event(newnp,
930 		    eval_dup(np->u.event.epname, ex, events),
931 		    eval_dup(np->u.event.eexprlist, ex, events)));
932 
933 	case T_FUNC:
934 		return (tree_func(np->u.func.s,
935 		    eval_dup(np->u.func.arglist, ex, events),
936 		    np->file, np->line));
937 
938 	case T_QUOTE:
939 		newnp = newnode(T_QUOTE, np->file, np->line);
940 		newnp->u.quote.s = np->u.quote.s;
941 		return (newnp);
942 
943 	case T_NUM:
944 		newnp = newnode(T_NUM, np->file, np->line);
945 		newnp->u.ull = np->u.ull;
946 		return (newnp);
947 
948 	default:
949 		outfl(O_DIE, np->file, np->line,
950 		    "eval_dup: unexpected node type: %s",
951 		    ptree_nodetype2str(np->t));
952 	}
953 	/*NOTREACHED*/
954 	return (0);
955 }
956 
957 /*
958  * eval_potential -- see if constraint is potentially true
959  *
960  * this function is used at instance tree creation time to see if
961  * any constraints are already known to be false.  if this function
962  * returns false, then the constraint will always be false and there's
963  * no need to include the propagation arrow in the instance tree.
964  *
965  * if this routine returns true, either the constraint is known to
966  * be always true (so there's no point in attaching the constraint
967  * to the propagation arrow in the instance tree), or the constraint
968  * contains "deferred" expressions like global variables or poller calls
969  * and so it must be evaluated during calls to fme_eval().  in this last
970  * case, where a constraint needs to be attached to the propagation arrow
971  * in the instance tree, this routine returns a newly created constraint
972  * in *newc where all the non-deferred things have been filled in.
973  *
974  * so in summary:
975  *
976  *	return of false: constraint can never be true, *newc will be NULL.
977  *
978  *	return of true with *newc unchanged: constraint will always be true.
979  *
980  *	return of true with *newc changed: use new constraint in *newc.
981  *
982  * the lookup table for all explicit iterators, ex, is passed in.
983  *
984  * *newc can either be NULL on entry, or if can contain constraints from
985  * previous calls to eval_potential() (i.e. for building up an instance
986  * tree constraint from several potential constraints).  if *newc already
987  * contains constraints, anything added to it will be joined by adding
988  * a T_AND node at the top of *newc.
989  */
990 int
991 eval_potential(struct node *np, struct lut *ex, struct node *events[],
992 	    struct node **newc, struct config *croot)
993 {
994 	struct node *newnp;
995 	struct evalue value;
996 
997 	if (eval_expr(np, ex, events, NULL, croot, NULL, 1, &value) == 0) {
998 		/*
999 		 * couldn't eval expression because
1000 		 * it contains deferred items.  make
1001 		 * a duplicate expression with all the
1002 		 * non-deferred items expanded.
1003 		 */
1004 		newnp = eval_dup(np, ex, events);
1005 
1006 		if (*newc == NULL) {
1007 			/*
1008 			 * constraint is potentially true if deferred
1009 			 * expression in newnp is true.  *newc was NULL
1010 			 * so new constraint is just the one in newnp.
1011 			 */
1012 			*newc = newnp;
1013 			return (1);
1014 		} else {
1015 			/*
1016 			 * constraint is potentially true if deferred
1017 			 * expression in newnp is true.  *newc already
1018 			 * contained a constraint so add an AND with the
1019 			 * constraint in newnp.
1020 			 */
1021 			*newc = tree_expr(T_AND, *newc, newnp);
1022 			return (1);
1023 		}
1024 	} else if (value.t == UNDEFINED) {
1025 		/* constraint can never be true */
1026 		return (0);
1027 	} else if (value.t == UINT64 && value.v == 0) {
1028 		/* constraint can never be true */
1029 		return (0);
1030 	} else {
1031 		/* constraint is always true (nothing deferred to eval) */
1032 		return (1);
1033 	}
1034 }
1035 
1036 static int
1037 check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype,
1038 		struct node *np)
1039 {
1040 	/* auto-convert T_NAMES to strings */
1041 	if (lp->t == NODEPTR && ((struct node *)(uintptr_t)(lp->v))->t ==
1042 	    T_NAME) {
1043 		char *s = ipath2str(NULL,
1044 		    ipath((struct node *)(uintptr_t)lp->v));
1045 		lp->t = STRING;
1046 		lp->v = (uintptr_t)stable(s);
1047 		FREE(s);
1048 		out(O_ALTFP|O_VERB2, "convert lhs path to \"%s\"",
1049 		    (char *)(uintptr_t)lp->v);
1050 	}
1051 	if (rp != NULL &&
1052 	    rp->t == NODEPTR && ((struct node *)(uintptr_t)(rp->v))->t ==
1053 	    T_NAME) {
1054 		char *s = ipath2str(NULL,
1055 		    ipath((struct node *)(uintptr_t)rp->v));
1056 		rp->t = STRING;
1057 		rp->v = (uintptr_t)stable(s);
1058 		FREE(s);
1059 		out(O_ALTFP|O_VERB2, "convert rhs path to \"%s\"",
1060 		    (char *)(uintptr_t)rp->v);
1061 	}
1062 
1063 	/* auto-convert strings to numbers */
1064 	if (dtype == UINT64) {
1065 		if (lp->t == STRING) {
1066 			lp->t = UINT64;
1067 			lp->v = strtoull((char *)(uintptr_t)lp->v, NULL, 0);
1068 		}
1069 		if (rp != NULL && rp->t == STRING) {
1070 			rp->t = UINT64;
1071 			rp->v = strtoull((char *)(uintptr_t)rp->v, NULL, 0);
1072 		}
1073 	}
1074 
1075 	if (dtype != UNDEFINED && lp->t != dtype) {
1076 		outfl(O_DIE, np->file, np->line,
1077 		    "invalid datatype of argument for operation %s",
1078 		    ptree_nodetype2str(np->t));
1079 		/* NOTREACHED */
1080 		return (1);
1081 	}
1082 
1083 	if (rp != NULL && lp->t != rp->t) {
1084 		outfl(O_DIE, np->file, np->line,
1085 		    "mismatch in datatype of arguments for operation %s",
1086 		    ptree_nodetype2str(np->t));
1087 		/* NOTREACHED */
1088 		return (1);
1089 	}
1090 
1091 	return (0);
1092 }
1093 
1094 /*
1095  * eval_expr -- evaluate expression into *valuep
1096  *
1097  * the meaning of the return value depends on the input value of try.
1098  *
1099  * for try == 1: if any deferred items are encounted, bail out and return
1100  * false.  returns true if we made it through entire expression without
1101  * hitting any deferred items.
1102  *
1103  * for try == 0: return true if all operations were performed successfully.
1104  * return false if otherwise.  for example, any of the following conditions
1105  * will result in a false return value:
1106  *   - attempted use of an uninitialized global variable
1107  *   - failure in function evaluation
1108  *   - illegal arithmetic operation (argument out of range)
1109  */
1110 int
1111 eval_expr(struct node *np, struct lut *ex, struct node *events[],
1112 	struct lut **globals, struct config *croot, struct arrow *arrowp,
1113 	int try, struct evalue *valuep)
1114 {
1115 	struct evalue *gval;
1116 	struct evalue lval;
1117 	struct evalue rval;
1118 
1119 	if (np == NULL) {
1120 		valuep->t = UINT64;
1121 		valuep->v = 1;	/* no constraint means "true" */
1122 		return (1);
1123 	}
1124 
1125 	valuep->t = UNDEFINED;
1126 
1127 	switch (np->t) {
1128 	case T_GLOBID:
1129 		if (try)
1130 			return (0);
1131 
1132 		/*
1133 		 * only handle case of getting (and not setting) the value
1134 		 * of a global variable
1135 		 */
1136 		gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL);
1137 		if (gval == NULL) {
1138 			return (0);
1139 		} else {
1140 			valuep->t = gval->t;
1141 			valuep->v = gval->v;
1142 			return (1);
1143 		}
1144 
1145 	case T_ASSIGN:
1146 		if (try)
1147 			return (0);
1148 
1149 		/*
1150 		 * first evaluate rhs, then try to store value in lhs which
1151 		 * should be a global variable
1152 		 */
1153 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1154 		    arrowp, try, &rval))
1155 			return (0);
1156 
1157 		ASSERT(np->u.expr.left->t == T_GLOBID);
1158 		gval = lut_lookup(*globals,
1159 		    (void *)np->u.expr.left->u.globid.s, NULL);
1160 
1161 		if (gval == NULL) {
1162 			gval = MALLOC(sizeof (*gval));
1163 			*globals = lut_add(*globals,
1164 			    (void *) np->u.expr.left->u.globid.s, gval, NULL);
1165 		}
1166 
1167 		gval->t = rval.t;
1168 		gval->v = rval.v;
1169 
1170 		if (gval->t == UINT64) {
1171 			out(O_ALTFP|O_VERB2,
1172 			    "assign $%s=%llu",
1173 			    np->u.expr.left->u.globid.s, gval->v);
1174 		} else {
1175 			out(O_ALTFP|O_VERB2,
1176 			    "assign $%s=\"%s\"",
1177 			    np->u.expr.left->u.globid.s,
1178 			    (char *)(uintptr_t)gval->v);
1179 		}
1180 
1181 		/*
1182 		 * but always return true -- an assignment should not
1183 		 * cause a constraint to be false.
1184 		 */
1185 		valuep->t = UINT64;
1186 		valuep->v = 1;
1187 		return (1);
1188 
1189 	case T_EQ:
1190 #define	IMPLICIT_ASSIGN_IN_EQ
1191 #ifdef IMPLICIT_ASSIGN_IN_EQ
1192 		/*
1193 		 * if lhs is an uninitialized global variable, perform
1194 		 * an assignment.
1195 		 *
1196 		 * one insidious side effect of implicit assignment is
1197 		 * that the "==" operator does not return a Boolean if
1198 		 * implicit assignment was performed.
1199 		 */
1200 		if (try == 0 &&
1201 		    np->u.expr.left->t == T_GLOBID &&
1202 		    (gval = lut_lookup(*globals,
1203 		    (void *)np->u.expr.left->u.globid.s, NULL)) == NULL) {
1204 			if (!eval_expr(np->u.expr.right, ex, events, globals,
1205 			    croot, arrowp, try, &rval))
1206 				return (0);
1207 
1208 			gval = MALLOC(sizeof (*gval));
1209 			*globals = lut_add(*globals,
1210 			    (void *) np->u.expr.left->u.globid.s,
1211 			    gval, NULL);
1212 
1213 			gval->t = rval.t;
1214 			gval->v = rval.v;
1215 			valuep->t = rval.t;
1216 			valuep->v = rval.v;
1217 			return (1);
1218 		}
1219 #endif  /* IMPLICIT_ASSIGN_IN_EQ */
1220 
1221 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1222 		    arrowp, try, &lval))
1223 			return (0);
1224 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1225 		    arrowp, try, &rval))
1226 			return (0);
1227 		if (rval.t == UINT64 || lval.t == UINT64) {
1228 			if (check_expr_args(&lval, &rval, UINT64, np))
1229 				return (0);
1230 		} else {
1231 			if (check_expr_args(&lval, &rval, UNDEFINED, np))
1232 				return (0);
1233 		}
1234 
1235 		valuep->t = UINT64;
1236 		valuep->v = (lval.v == rval.v);
1237 		return (1);
1238 
1239 	case T_LT:
1240 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1241 		    arrowp, try, &lval))
1242 			return (0);
1243 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1244 		    arrowp, try, &rval))
1245 			return (0);
1246 		if (check_expr_args(&lval, &rval, UINT64, np))
1247 			return (0);
1248 
1249 		valuep->t = UINT64;
1250 		valuep->v = (lval.v < rval.v);
1251 		return (1);
1252 
1253 	case T_LE:
1254 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1255 		    arrowp, try, &lval))
1256 			return (0);
1257 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1258 		    arrowp, try, &rval))
1259 			return (0);
1260 		if (check_expr_args(&lval, &rval, UINT64, np))
1261 			return (0);
1262 
1263 		valuep->t = UINT64;
1264 		valuep->v = (lval.v <= rval.v);
1265 		return (1);
1266 
1267 	case T_GT:
1268 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1269 		    arrowp, try, &lval))
1270 			return (0);
1271 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1272 		    arrowp, try, &rval))
1273 			return (0);
1274 		if (check_expr_args(&lval, &rval, UINT64, np))
1275 			return (0);
1276 
1277 		valuep->t = UINT64;
1278 		valuep->v = (lval.v > rval.v);
1279 		return (1);
1280 
1281 	case T_GE:
1282 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1283 		    arrowp, try, &lval))
1284 			return (0);
1285 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1286 		    arrowp, try, &rval))
1287 			return (0);
1288 		if (check_expr_args(&lval, &rval, UINT64, np))
1289 			return (0);
1290 
1291 		valuep->t = UINT64;
1292 		valuep->v = (lval.v >= rval.v);
1293 		return (1);
1294 
1295 	case T_BITAND:
1296 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1297 		    arrowp, try, &lval))
1298 			return (0);
1299 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1300 		    arrowp, try, &rval))
1301 			return (0);
1302 		if (check_expr_args(&lval, &rval, UINT64, np))
1303 			return (0);
1304 
1305 		valuep->t = lval.t;
1306 		valuep->v = (lval.v & rval.v);
1307 		return (1);
1308 
1309 	case T_BITOR:
1310 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1311 		    arrowp, try, &lval))
1312 			return (0);
1313 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1314 		    arrowp, try, &rval))
1315 			return (0);
1316 		if (check_expr_args(&lval, &rval, UINT64, np))
1317 			return (0);
1318 
1319 		valuep->t = lval.t;
1320 		valuep->v = (lval.v | rval.v);
1321 		return (1);
1322 
1323 	case T_BITXOR:
1324 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1325 		    arrowp, try, &lval))
1326 			return (0);
1327 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1328 		    arrowp, try, &rval))
1329 			return (0);
1330 		if (check_expr_args(&lval, &rval, UINT64, np))
1331 			return (0);
1332 
1333 		valuep->t = lval.t;
1334 		valuep->v = (lval.v ^ rval.v);
1335 		return (1);
1336 
1337 	case T_BITNOT:
1338 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1339 		    arrowp, try, &lval))
1340 			return (0);
1341 		ASSERT(np->u.expr.right == NULL);
1342 		if (check_expr_args(&lval, NULL, UINT64, np))
1343 			return (0);
1344 
1345 		valuep->t = UINT64;
1346 		valuep->v = ~ lval.v;
1347 		return (1);
1348 
1349 	case T_LSHIFT:
1350 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1351 		    arrowp, try, &lval))
1352 			return (0);
1353 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1354 		    arrowp, try, &rval))
1355 			return (0);
1356 		if (check_expr_args(&lval, &rval, UINT64, np))
1357 			return (0);
1358 
1359 		valuep->t = UINT64;
1360 		valuep->v = (lval.v << rval.v);
1361 		return (1);
1362 
1363 	case T_RSHIFT:
1364 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1365 		    arrowp, try, &lval))
1366 			return (0);
1367 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1368 		    arrowp, try, &rval))
1369 			return (0);
1370 		if (check_expr_args(&lval, &rval, UINT64, np))
1371 			return (0);
1372 
1373 		valuep->t = UINT64;
1374 		valuep->v = (lval.v >> rval.v);
1375 		return (1);
1376 
1377 	case T_CONDIF: {
1378 		struct node *retnp;
1379 		int dotrue = 0;
1380 
1381 		/*
1382 		 * evaluate
1383 		 *	expression ? stmtA [ : stmtB ]
1384 		 *
1385 		 * first see if expression is true or false, then determine
1386 		 * if stmtA (or stmtB, if it exists) should be evaluated.
1387 		 *
1388 		 * "dotrue = 1" means stmtA should be evaluated.
1389 		 */
1390 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1391 		    arrowp, try, &lval))
1392 			return (0);
1393 
1394 		if (lval.t != UNDEFINED && lval.v != 0)
1395 			dotrue = 1;
1396 
1397 		ASSERT(np->u.expr.right != NULL);
1398 		if (np->u.expr.right->t == T_CONDELSE) {
1399 			if (dotrue)
1400 				retnp = np->u.expr.right->u.expr.left;
1401 			else
1402 				retnp = np->u.expr.right->u.expr.right;
1403 		} else {
1404 			/* no ELSE clause */
1405 			if (dotrue)
1406 				retnp = np->u.expr.right;
1407 			else {
1408 				outfl(O_DIE, np->file, np->line,
1409 				    "eval_expr: missing condelse");
1410 			}
1411 		}
1412 
1413 		if (!eval_expr(retnp, ex, events, globals, croot,
1414 		    arrowp, try, valuep))
1415 			return (0);
1416 		return (1);
1417 	}
1418 
1419 	case T_CONDELSE:
1420 		/*
1421 		 * shouldn't get here, since T_CONDELSE is supposed to be
1422 		 * evaluated as part of T_CONDIF
1423 		 */
1424 		out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s",
1425 		    ptree_nodetype2str(np->t));
1426 		/*NOTREACHED*/
1427 
1428 	case T_NE:
1429 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1430 		    arrowp, try, &lval))
1431 			return (0);
1432 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1433 		    arrowp, try, &rval))
1434 			return (0);
1435 		if (rval.t == UINT64 || lval.t == UINT64) {
1436 			if (check_expr_args(&lval, &rval, UINT64, np))
1437 				return (0);
1438 		} else {
1439 			if (check_expr_args(&lval, &rval, UNDEFINED, np))
1440 				return (0);
1441 		}
1442 
1443 		valuep->t = UINT64;
1444 		valuep->v = (lval.v != rval.v);
1445 		return (1);
1446 
1447 	case T_LIST:
1448 	case T_AND:
1449 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1450 		    arrowp, try, valuep)) {
1451 			/*
1452 			 * if lhs is unknown, still check rhs. If that
1453 			 * is false we can return false irrespective of lhs
1454 			 */
1455 			if (!try) {
1456 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
1457 				return (0);
1458 			}
1459 			if (!eval_expr(np->u.expr.right, ex, events, globals,
1460 			    croot, arrowp, try, valuep)) {
1461 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
1462 				return (0);
1463 			}
1464 			if (valuep->v != 0) {
1465 				np->u.expr.temp = EXPR_TEMP_LHS_UNK;
1466 				return (0);
1467 			}
1468 		}
1469 		if (valuep->v == 0) {
1470 			valuep->t = UINT64;
1471 			return (1);
1472 		}
1473 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1474 		    arrowp, try, valuep)) {
1475 			np->u.expr.temp = EXPR_TEMP_RHS_UNK;
1476 			return (0);
1477 		}
1478 		valuep->t = UINT64;
1479 		valuep->v = valuep->v == 0 ? 0 : 1;
1480 		return (1);
1481 
1482 	case T_OR:
1483 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1484 		    arrowp, try, valuep)) {
1485 			/*
1486 			 * if lhs is unknown, still check rhs. If that
1487 			 * is true we can return true irrespective of lhs
1488 			 */
1489 			if (!try) {
1490 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
1491 				return (0);
1492 			}
1493 			if (!eval_expr(np->u.expr.right, ex, events, globals,
1494 			    croot, arrowp, try, valuep)) {
1495 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
1496 				return (0);
1497 			}
1498 			if (valuep->v == 0) {
1499 				np->u.expr.temp = EXPR_TEMP_LHS_UNK;
1500 				return (0);
1501 			}
1502 		}
1503 		if (valuep->v != 0) {
1504 			valuep->t = UINT64;
1505 			valuep->v = 1;
1506 			return (1);
1507 		}
1508 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1509 		    arrowp, try, valuep)) {
1510 			np->u.expr.temp = EXPR_TEMP_RHS_UNK;
1511 			return (0);
1512 		}
1513 		valuep->t = UINT64;
1514 		valuep->v = valuep->v == 0 ? 0 : 1;
1515 		return (1);
1516 
1517 	case T_NOT:
1518 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1519 		    arrowp, try, valuep))
1520 			return (0);
1521 		valuep->t = UINT64;
1522 		valuep->v = ! valuep->v;
1523 		return (1);
1524 
1525 	case T_ADD:
1526 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1527 		    arrowp, try, &lval))
1528 			return (0);
1529 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1530 		    arrowp, try, &rval))
1531 			return (0);
1532 		if (check_expr_args(&lval, &rval, UINT64, np))
1533 			return (0);
1534 
1535 		valuep->t = lval.t;
1536 		valuep->v = lval.v + rval.v;
1537 		return (1);
1538 
1539 	case T_SUB:
1540 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1541 		    arrowp, try, &lval))
1542 			return (0);
1543 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1544 		    arrowp, try, &rval))
1545 			return (0);
1546 		if (check_expr_args(&lval, &rval, UINT64, np))
1547 			return (0);
1548 
1549 		/* since valuep is unsigned, return false if lval.v < rval.v */
1550 		if (lval.v < rval.v) {
1551 			outfl(O_DIE, np->file, np->line,
1552 			    "eval_expr: T_SUB result is out of range");
1553 		}
1554 
1555 		valuep->t = lval.t;
1556 		valuep->v = lval.v - rval.v;
1557 		return (1);
1558 
1559 	case T_MUL:
1560 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1561 		    arrowp, try, &lval))
1562 			return (0);
1563 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1564 		    arrowp, try, &rval))
1565 			return (0);
1566 		if (check_expr_args(&lval, &rval, UINT64, np))
1567 			return (0);
1568 
1569 		valuep->t = lval.t;
1570 		valuep->v = lval.v * rval.v;
1571 		return (1);
1572 
1573 	case T_DIV:
1574 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1575 		    arrowp, try, &lval))
1576 			return (0);
1577 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1578 		    arrowp, try, &rval))
1579 			return (0);
1580 		if (check_expr_args(&lval, &rval, UINT64, np))
1581 			return (0);
1582 
1583 		/* return false if dividing by zero */
1584 		if (rval.v == 0) {
1585 			outfl(O_DIE, np->file, np->line,
1586 			    "eval_expr: T_DIV division by zero");
1587 		}
1588 
1589 		valuep->t = lval.t;
1590 		valuep->v = lval.v / rval.v;
1591 		return (1);
1592 
1593 	case T_MOD:
1594 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1595 		    arrowp, try, &lval))
1596 			return (0);
1597 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1598 		    arrowp, try, &rval))
1599 			return (0);
1600 		if (check_expr_args(&lval, &rval, UINT64, np))
1601 			return (0);
1602 
1603 		/* return false if dividing by zero */
1604 		if (rval.v == 0) {
1605 			outfl(O_DIE, np->file, np->line,
1606 			    "eval_expr: T_MOD division by zero");
1607 		}
1608 
1609 		valuep->t = lval.t;
1610 		valuep->v = lval.v % rval.v;
1611 		return (1);
1612 
1613 	case T_NAME:
1614 		if (try) {
1615 			struct iterinfo *iterinfop;
1616 			struct node *np1, *np2;
1617 			int i, gotmatch = 0;
1618 
1619 			/*
1620 			 * Check if we have an exact match of the nonwildcarded
1621 			 * path in oldepname - if so we can just use the
1622 			 * full wildcarded path in epname.
1623 			 */
1624 			for (i = 0; i < 1; i++) {
1625 				for (np1 = np,
1626 				    np2 = events[i]->u.event.oldepname;
1627 				    np1 != NULL && np2 != NULL;
1628 				    np1 = np1->u.name.next,
1629 				    np2 = np2->u.name.next) {
1630 					if (strcmp(np1->u.name.s,
1631 					    np2->u.name.s) != 0)
1632 						break;
1633 					if (np1->u.name.child->t !=
1634 					    np2->u.name.child->t)
1635 						break;
1636 					if (np1->u.name.child->t == T_NUM &&
1637 					    np1->u.name.child->u.ull !=
1638 					    np2->u.name.child->u.ull)
1639 						break;
1640 					if (np1->u.name.child->t == T_NAME &&
1641 					    strcmp(np1->u.name.child->u.name.s,
1642 					    np2->u.name.child->u.name.s) != 0)
1643 						break;
1644 					gotmatch++;
1645 				}
1646 				if (np1 == NULL && np2 == NULL) {
1647 					valuep->t = NODEPTR;
1648 					valuep->v = (uintptr_t)
1649 					    events[i]->u.event.epname;
1650 					return (1);
1651 				}
1652 			}
1653 			if (!gotmatch) {
1654 				/*
1655 				 * we're not wildcarding. However at
1656 				 * itree_create() time, we can also expand
1657 				 * simple iterators - so check for those.
1658 				 */
1659 				iterinfop = lut_lookup(ex, (void *)np->u.name.s,
1660 				    NULL);
1661 				if (iterinfop != NULL) {
1662 					valuep->t = UINT64;
1663 					valuep->v =
1664 					    (unsigned long long)iterinfop->num;
1665 					return (1);
1666 				}
1667 			}
1668 			/*
1669 			 * For anything else we'll have to wait for eval_dup().
1670 			 */
1671 			return (0);
1672 		}
1673 
1674 		/* return address of struct node */
1675 		valuep->t = NODEPTR;
1676 		valuep->v = (uintptr_t)np;
1677 		return (1);
1678 
1679 	case T_QUOTE:
1680 		valuep->t = STRING;
1681 		valuep->v = (uintptr_t)np->u.quote.s;
1682 		return (1);
1683 
1684 	case T_FUNC:
1685 		return (eval_func(np, ex, events, np->u.func.arglist,
1686 		    globals, croot, arrowp, try, valuep));
1687 
1688 	case T_NUM:
1689 		valuep->t = UINT64;
1690 		valuep->v = np->u.ull;
1691 		return (1);
1692 
1693 	default:
1694 		outfl(O_DIE, np->file, np->line,
1695 		    "eval_expr: unexpected node type: %s",
1696 		    ptree_nodetype2str(np->t));
1697 	}
1698 	/*NOTREACHED*/
1699 	return (0);
1700 }
1701 
1702 /*
1703  * eval_fru() and eval_asru() don't do much, but are called from a number
1704  * of places.
1705  */
1706 static struct node *
1707 eval_fru(struct node *np)
1708 {
1709 	ASSERT(np->t == T_NAME);
1710 	return (np);
1711 }
1712 
1713 static struct node *
1714 eval_asru(struct node *np)
1715 {
1716 	ASSERT(np->t == T_NAME);
1717 	return (np);
1718 }
1719