xref: /illumos-gate/usr/src/cmd/fm/modules/common/eversholt/eval.c (revision b7d3956b92a285d8dac2c7f5f7e28d2ef5347ef8)
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 2008 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 		if (arrowp->head->myevent->count == 0)
503 			return (0);
504 
505 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
506 		    "setpayloadprop: %s: %s=",
507 		    arrowp->tail->myevent->enode->u.event.ename->u.name.s,
508 		    np->u.expr.left->u.quote.s);
509 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right);
510 
511 		/*
512 		 * allocate a struct evalue to hold the payload property's
513 		 * value, unless we've been here already, in which case we
514 		 * might calculate a different value, but we'll store it
515 		 * in the already-allocated struct evalue.
516 		 */
517 		if ((payloadvalp = (struct evalue *)lut_lookup(
518 		    arrowp->tail->myevent->payloadprops,
519 		    (void *)np->u.expr.left->u.quote.s, NULL)) == NULL) {
520 			payloadvalp = MALLOC(sizeof (*payloadvalp));
521 			alloced = 1;
522 		}
523 
524 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
525 		    arrowp, try, payloadvalp)) {
526 			out(O_ALTFP|O_VERB2, " (cannot eval)");
527 			if (alloced)
528 				FREE(payloadvalp);
529 			return (0);
530 		} else {
531 			if (payloadvalp->t == UNDEFINED) {
532 				/* function is always true */
533 				out(O_ALTFP|O_VERB2, " (undefined)");
534 				valuep->t = UINT64;
535 				valuep->v = 1;
536 				return (1);
537 			}
538 			if (payloadvalp->t == UINT64)
539 				out(O_ALTFP|O_VERB2,
540 				    " (%llu)", payloadvalp->v);
541 			else
542 				out(O_ALTFP|O_VERB2, " (\"%s\")",
543 				    (char *)(uintptr_t)payloadvalp->v);
544 		}
545 
546 		/* add to table of payload properties for current problem */
547 		arrowp->tail->myevent->payloadprops =
548 		    lut_add(arrowp->tail->myevent->payloadprops,
549 		    (void *)np->u.expr.left->u.quote.s,
550 		    (void *)payloadvalp, NULL);
551 
552 		/* function is always true */
553 		valuep->t = UINT64;
554 		valuep->v = 1;
555 		return (1);
556 	} else if (funcname == L_setserdn || funcname == L_setserdt ||
557 	    funcname == L_setserdsuffix || funcname == L_setserdincrement) {
558 		struct evalue *serdvalp;
559 		int alloced = 0;
560 		char *str;
561 		struct event *flt = arrowp->tail->myevent;
562 
563 		if (arrowp->head->myevent->count == 0)
564 			return (0);
565 
566 		if (funcname == L_setserdn)
567 			str = "n";
568 		else if (funcname == L_setserdt)
569 			str = "t";
570 		else if (funcname == L_setserdsuffix)
571 			str = "suffix";
572 		else if (funcname == L_setserdincrement)
573 			str = "increment";
574 
575 		/*
576 		 * allocate a struct evalue to hold the serd property's
577 		 * value, unless we've been here already, in which case we
578 		 * might calculate a different value, but we'll store it
579 		 * in the already-allocated struct evalue.
580 		 */
581 		if ((serdvalp = (struct evalue *)lut_lookup(flt->serdprops,
582 		    (void *)str, NULL)) == NULL) {
583 			serdvalp = MALLOC(sizeof (*serdvalp));
584 			alloced = 1;
585 		}
586 
587 		if (!eval_expr(np, ex, events, globals, croot, arrowp, try,
588 		    serdvalp)) {
589 			outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
590 			    "setserd%s: %s: ", str,
591 			    flt->enode->u.event.ename->u.name.s);
592 			ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np);
593 			out(O_ALTFP|O_VERB2, " (cannot eval)");
594 			if (alloced)
595 				FREE(serdvalp);
596 			return (0);
597 		} else if (serdvalp->t == UNDEFINED) {
598 			outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
599 			    "setserd%s: %s: ", str,
600 			    flt->enode->u.event.ename->u.name.s);
601 			ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np);
602 			out(O_ALTFP|O_VERB2, " (undefined)");
603 		} else {
604 			outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
605 			    "setserd%s: %s: ", str,
606 			    flt->enode->u.event.ename->u.name.s);
607 			ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np);
608 			if ((funcname == L_setserdincrement ||
609 			    funcname == L_setserdn) && serdvalp->t == STRING) {
610 				serdvalp->t = UINT64;
611 				serdvalp->v = strtoull((char *)
612 				    (uintptr_t)serdvalp->v, NULL, 0);
613 			}
614 			if (funcname == L_setserdt && serdvalp->t == UINT64) {
615 				int len = snprintf(NULL, 0, "%lldns",
616 				    serdvalp->v);
617 				char *buf = MALLOC(len + 1);
618 
619 				(void) snprintf(buf, len + 1, "%lldns",
620 				    serdvalp->v);
621 				serdvalp->t = STRING;
622 				serdvalp->v = (uintptr_t)stable(buf);
623 				FREE(buf);
624 			}
625 			if (serdvalp->t == UINT64)
626 				out(O_ALTFP|O_VERB2, " (%llu)", serdvalp->v);
627 			else
628 				out(O_ALTFP|O_VERB2, " (\"%s\")",
629 				    (char *)(uintptr_t)serdvalp->v);
630 			flt->serdprops = lut_add(flt->serdprops, (void *)str,
631 			    (void *)serdvalp, NULL);
632 		}
633 		valuep->t = UINT64;
634 		valuep->v = 1;
635 		return (1);
636 	} else if (funcname == L_payloadprop_defined) {
637 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
638 		    "payloadprop_defined(\"%s\") ", np->u.quote.s);
639 
640 		if (arrowp->head->myevent->count == 0) {
641 			/*
642 			 * Haven't seen this ereport yet, so must defer
643 			 */
644 			out(O_ALTFP|O_VERB2, "ereport not yet seen - defer.");
645 			return (0);
646 		} else if (platform_payloadprop(np, NULL)) {
647 			/* platform_payloadprop() returned false */
648 			valuep->v = 0;
649 			out(O_ALTFP|O_VERB2, "not found.");
650 		} else {
651 			valuep->v = 1;
652 			out(O_ALTFP|O_VERB2, "found.");
653 		}
654 		valuep->t = UINT64;
655 		return (1);
656 	} else if (funcname == L_payloadprop_contains) {
657 		int nvals;
658 		struct evalue *vals;
659 		struct evalue cmpval;
660 
661 		ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t));
662 		ASSERTinfo(np->u.expr.left->t == T_QUOTE,
663 		    ptree_nodetype2str(np->u.expr.left->t));
664 
665 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
666 		    "payloadprop_contains(\"%s\", ",
667 		    np->u.expr.left->u.quote.s);
668 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right);
669 		out(O_ALTFP|O_VERB2|O_NONL, ") ");
670 
671 		/* evaluate the expression we're comparing against */
672 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
673 		    arrowp, try, &cmpval)) {
674 			out(O_ALTFP|O_VERB2|O_NONL,
675 			    "(cannot eval) ");
676 			return (0);
677 		} else {
678 			switch (cmpval.t) {
679 			case UNDEFINED:
680 				out(O_ALTFP|O_VERB2, "(undefined type)");
681 				break;
682 
683 			case UINT64:
684 				out(O_ALTFP|O_VERB2,
685 				    "(%llu) ", cmpval.v);
686 				break;
687 
688 			case STRING:
689 				out(O_ALTFP|O_VERB2,
690 				    "(\"%s\") ", (char *)(uintptr_t)cmpval.v);
691 				break;
692 
693 			case NODEPTR:
694 				out(O_ALTFP|O_VERB2|O_NONL, "(");
695 				ptree_name_iter(O_ALTFP|O_VERB2|O_NONL,
696 				    (struct node *)(uintptr_t)(cmpval.v));
697 				out(O_ALTFP|O_VERB2, ") ");
698 				break;
699 			}
700 		}
701 
702 		/* get the payload values and check for a match */
703 		vals = platform_payloadprop_values(np->u.expr.left->u.quote.s,
704 		    &nvals);
705 		valuep->t = UINT64;
706 		valuep->v = 0;
707 		if (arrowp->head->myevent->count == 0) {
708 			/*
709 			 * Haven't seen this ereport yet, so must defer
710 			 */
711 			out(O_ALTFP|O_VERB2, "ereport not yet seen - defer.");
712 			return (0);
713 		} else if (nvals == 0) {
714 			out(O_ALTFP|O_VERB2, "not found.");
715 			return (1);
716 		} else {
717 			struct evalue preval;
718 			int i;
719 
720 			out(O_ALTFP|O_VERB2|O_NONL, "found %d values ", nvals);
721 
722 			for (i = 0; i < nvals; i++) {
723 
724 				preval.t = vals[i].t;
725 				preval.v = vals[i].v;
726 
727 				if (check_expr_args(&vals[i], &cmpval,
728 				    UNDEFINED, np))
729 					continue;
730 
731 				/*
732 				 * If we auto-converted the value to a
733 				 * string, we need to free the
734 				 * original tree value.
735 				 */
736 				if (preval.t == NODEPTR &&
737 				    ((struct node *)(uintptr_t)(preval.v))->t ==
738 				    T_NAME) {
739 					tree_free((struct node *)(uintptr_t)
740 					    preval.v);
741 				}
742 
743 				if (vals[i].v == cmpval.v) {
744 					valuep->v = 1;
745 					break;
746 				}
747 			}
748 
749 			if (valuep->v)
750 				out(O_ALTFP|O_VERB2, "match.");
751 			else
752 				out(O_ALTFP|O_VERB2, "no match.");
753 
754 			for (i = 0; i < nvals; i++) {
755 				if (vals[i].t == NODEPTR) {
756 					tree_free((struct node *)(uintptr_t)
757 					    vals[i].v);
758 					break;
759 				}
760 			}
761 			FREE(vals);
762 		}
763 		return (1);
764 	} else if (funcname == L_confcall) {
765 		return (!platform_confcall(np, globals, croot, arrowp, valuep));
766 	} else
767 		outfl(O_DIE, np->file, np->line,
768 		    "eval_func: unexpected func: %s", funcname);
769 	/*NOTREACHED*/
770 	return (0);
771 }
772 
773 /*
774  * defines for u.expr.temp - these are used for T_OR and T_AND so that if
775  * we worked out that part of the expression was true or false during an
776  * earlier eval_expr, then we don't need to dup that part.
777  */
778 
779 #define	EXPR_TEMP_BOTH_UNK	0
780 #define	EXPR_TEMP_LHS_UNK	1
781 #define	EXPR_TEMP_RHS_UNK	2
782 
783 static struct node *
784 eval_dup(struct node *np, struct lut *ex, struct node *events[])
785 {
786 	struct node *newnp;
787 
788 	if (np == NULL)
789 		return (NULL);
790 
791 	switch (np->t) {
792 	case T_GLOBID:
793 		return (tree_globid(np->u.globid.s, np->file, np->line));
794 
795 	case T_ASSIGN:
796 	case T_CONDIF:
797 	case T_CONDELSE:
798 	case T_NE:
799 	case T_EQ:
800 	case T_LT:
801 	case T_LE:
802 	case T_GT:
803 	case T_GE:
804 	case T_BITAND:
805 	case T_BITOR:
806 	case T_BITXOR:
807 	case T_BITNOT:
808 	case T_LSHIFT:
809 	case T_RSHIFT:
810 	case T_NOT:
811 	case T_ADD:
812 	case T_SUB:
813 	case T_MUL:
814 	case T_DIV:
815 	case T_MOD:
816 		return (tree_expr(np->t,
817 		    eval_dup(np->u.expr.left, ex, events),
818 		    eval_dup(np->u.expr.right, ex, events)));
819 	case T_LIST:
820 	case T_AND:
821 		switch (np->u.expr.temp) {
822 		case EXPR_TEMP_LHS_UNK:
823 			return (eval_dup(np->u.expr.left, ex, events));
824 		case EXPR_TEMP_RHS_UNK:
825 			return (eval_dup(np->u.expr.right, ex, events));
826 		default:
827 			return (tree_expr(np->t,
828 			    eval_dup(np->u.expr.left, ex, events),
829 			    eval_dup(np->u.expr.right, ex, events)));
830 		}
831 
832 	case T_OR:
833 		switch (np->u.expr.temp) {
834 		case EXPR_TEMP_LHS_UNK:
835 			return (eval_dup(np->u.expr.left, ex, events));
836 		case EXPR_TEMP_RHS_UNK:
837 			return (eval_dup(np->u.expr.right, ex, events));
838 		default:
839 			return (tree_expr(T_OR,
840 			    eval_dup(np->u.expr.left, ex, events),
841 			    eval_dup(np->u.expr.right, ex, events)));
842 		}
843 
844 	case T_NAME: {
845 		struct iterinfo *iterinfop;
846 		int got_matchf = 0;
847 		int got_matcht = 0;
848 		struct evalue value;
849 		struct node *np1f, *np2f, *np1t, *np2t, *retp = NULL;
850 		struct node *npstart, *npcont, *npend, *npref, *newnp, *nprest;
851 
852 		/*
853 		 * Check if we already have a match of the nonwildcarded path
854 		 * in oldepname (check both to and from events).
855 		 */
856 		for (np1f = np, np2f = events[0]->u.event.oldepname;
857 		    np1f != NULL && np2f != NULL;
858 		    np1f = np1f->u.name.next, np2f = np2f->u.name.next) {
859 			if (strcmp(np1f->u.name.s, np2f->u.name.s) != 0)
860 				break;
861 			if (np1f->u.name.child->t != np2f->u.name.child->t)
862 				break;
863 			if (np1f->u.name.child->t == T_NUM &&
864 			    np1f->u.name.child->u.ull !=
865 			    np2f->u.name.child->u.ull)
866 				break;
867 			if (np1f->u.name.child->t == T_NAME &&
868 			    strcmp(np1f->u.name.child->u.name.s,
869 			    np2f->u.name.child->u.name.s) != 0)
870 				break;
871 			got_matchf++;
872 		}
873 		for (np1t = np, np2t = events[1]->u.event.oldepname;
874 		    np1t != NULL && np2t != NULL;
875 		    np1t = np1t->u.name.next, np2t = np2t->u.name.next) {
876 			if (strcmp(np1t->u.name.s, np2t->u.name.s) != 0)
877 				break;
878 			if (np1t->u.name.child->t != np2t->u.name.child->t)
879 				break;
880 			if (np1t->u.name.child->t == T_NUM &&
881 			    np1t->u.name.child->u.ull !=
882 			    np2t->u.name.child->u.ull)
883 				break;
884 			if (np1t->u.name.child->t == T_NAME &&
885 			    strcmp(np1t->u.name.child->u.name.s,
886 			    np2t->u.name.child->u.name.s) != 0)
887 				break;
888 			got_matcht++;
889 		}
890 		nprest = np;
891 		if (got_matchf || got_matcht) {
892 			/*
893 			 * so we are wildcarding. Copy ewname in full, plus
894 			 * matching section of oldepname. Use whichever gives
895 			 * the closest match.
896 			 */
897 			if (got_matchf > got_matcht) {
898 				npstart = events[0]->u.event.ewname;
899 				npcont = events[0]->u.event.oldepname;
900 				npend = np2f;
901 				nprest = np1f;
902 			} else {
903 				npstart = events[1]->u.event.ewname;
904 				npcont = events[1]->u.event.oldepname;
905 				npend = np2t;
906 				nprest = np1t;
907 			}
908 			for (npref = npstart; npref != NULL;
909 			    npref = npref->u.name.next) {
910 				newnp = newnode(T_NAME, np->file, np->line);
911 				newnp->u.name.t = npref->u.name.t;
912 				newnp->u.name.s = npref->u.name.s;
913 				newnp->u.name.last = newnp;
914 				newnp->u.name.it = npref->u.name.it;
915 				newnp->u.name.cp = npref->u.name.cp;
916 				newnp->u.name.child =
917 				    newnode(T_NUM, np->file, np->line);
918 				if (eval_expr(npref->u.name.child, ex, events,
919 				    NULL, NULL, NULL, 1, &value) == 0 ||
920 				    value.t != UINT64) {
921 					outfl(O_DIE, np->file, np->line,
922 					    "eval_dup: could not resolve "
923 					    "iterator of %s", np->u.name.s);
924 				}
925 				newnp->u.name.child->u.ull = value.v;
926 				if (retp == NULL) {
927 					retp = newnp;
928 				} else {
929 					retp->u.name.last->u.name.next = newnp;
930 					retp->u.name.last = newnp;
931 				}
932 			}
933 			for (npref = npcont; npref != NULL && npref != npend;
934 			    npref = npref->u.name.next) {
935 				newnp = newnode(T_NAME, np->file, np->line);
936 				newnp->u.name.t = npref->u.name.t;
937 				newnp->u.name.s = npref->u.name.s;
938 				newnp->u.name.last = newnp;
939 				newnp->u.name.it = npref->u.name.it;
940 				newnp->u.name.cp = npref->u.name.cp;
941 				newnp->u.name.child =
942 				    newnode(T_NUM, np->file, np->line);
943 				if (eval_expr(npref->u.name.child, ex, events,
944 				    NULL, NULL, NULL, 1, &value) == 0 ||
945 				    value.t != UINT64) {
946 					outfl(O_DIE, np->file, np->line,
947 					    "eval_dup: could not resolve "
948 					    "iterator of %s", np->u.name.s);
949 				}
950 				newnp->u.name.child->u.ull = value.v;
951 				if (retp == NULL) {
952 					retp = newnp;
953 				} else {
954 					retp->u.name.last->u.name.next = newnp;
955 					retp->u.name.last = newnp;
956 				}
957 			}
958 		} else {
959 			/*
960 			 * not wildcarding - check if explicit iterator
961 			 */
962 			iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
963 			if (iterinfop != NULL) {
964 				/* explicit iterator; not part of pathname */
965 				newnp = newnode(T_NUM, np->file, np->line);
966 				newnp->u.ull = iterinfop->num;
967 				return (newnp);
968 			}
969 		}
970 
971 		/*
972 		 * finally, whether wildcarding or not, we need to copy the
973 		 * remaining part of the path (if any). This must be defined
974 		 * absolutely (no more expansion/wildcarding).
975 		 */
976 		for (npref = nprest; npref != NULL;
977 		    npref = npref->u.name.next) {
978 			newnp = newnode(T_NAME, np->file, np->line);
979 			newnp->u.name.t = npref->u.name.t;
980 			newnp->u.name.s = npref->u.name.s;
981 			newnp->u.name.last = newnp;
982 			newnp->u.name.it = npref->u.name.it;
983 			newnp->u.name.cp = npref->u.name.cp;
984 			newnp->u.name.child =
985 			    newnode(T_NUM, np->file, np->line);
986 			if (eval_expr(npref->u.name.child, ex, events,
987 			    NULL, NULL, NULL, 1, &value) == 0 ||
988 			    value.t != UINT64) {
989 				outfl(O_DIE, np->file, np->line,
990 				    "eval_dup: could not resolve "
991 				    "iterator of %s", np->u.name.s);
992 			}
993 			newnp->u.name.child->u.ull = value.v;
994 			if (retp == NULL) {
995 				retp = newnp;
996 			} else {
997 				retp->u.name.last->u.name.next = newnp;
998 				retp->u.name.last = newnp;
999 			}
1000 		}
1001 		return (retp);
1002 	}
1003 
1004 	case T_EVENT:
1005 		newnp = newnode(T_NAME, np->file, np->line);
1006 
1007 		newnp->u.name.t = np->u.event.ename->u.name.t;
1008 		newnp->u.name.s = np->u.event.ename->u.name.s;
1009 		newnp->u.name.it = np->u.event.ename->u.name.it;
1010 		newnp->u.name.last = newnp;
1011 
1012 		return (tree_event(newnp,
1013 		    eval_dup(np->u.event.epname, ex, events),
1014 		    eval_dup(np->u.event.eexprlist, ex, events)));
1015 
1016 	case T_FUNC:
1017 		return (tree_func(np->u.func.s,
1018 		    eval_dup(np->u.func.arglist, ex, events),
1019 		    np->file, np->line));
1020 
1021 	case T_QUOTE:
1022 		newnp = newnode(T_QUOTE, np->file, np->line);
1023 		newnp->u.quote.s = np->u.quote.s;
1024 		return (newnp);
1025 
1026 	case T_NUM:
1027 		newnp = newnode(T_NUM, np->file, np->line);
1028 		newnp->u.ull = np->u.ull;
1029 		return (newnp);
1030 
1031 	case T_TIMEVAL:
1032 		newnp = newnode(T_TIMEVAL, np->file, np->line);
1033 		newnp->u.ull = np->u.ull;
1034 		return (newnp);
1035 
1036 	default:
1037 		outfl(O_DIE, np->file, np->line,
1038 		    "eval_dup: unexpected node type: %s",
1039 		    ptree_nodetype2str(np->t));
1040 	}
1041 	/*NOTREACHED*/
1042 	return (0);
1043 }
1044 
1045 /*
1046  * eval_potential -- see if constraint is potentially true
1047  *
1048  * this function is used at instance tree creation time to see if
1049  * any constraints are already known to be false.  if this function
1050  * returns false, then the constraint will always be false and there's
1051  * no need to include the propagation arrow in the instance tree.
1052  *
1053  * if this routine returns true, either the constraint is known to
1054  * be always true (so there's no point in attaching the constraint
1055  * to the propagation arrow in the instance tree), or the constraint
1056  * contains "deferred" expressions like global variables or poller calls
1057  * and so it must be evaluated during calls to fme_eval().  in this last
1058  * case, where a constraint needs to be attached to the propagation arrow
1059  * in the instance tree, this routine returns a newly created constraint
1060  * in *newc where all the non-deferred things have been filled in.
1061  *
1062  * so in summary:
1063  *
1064  *	return of false: constraint can never be true, *newc will be NULL.
1065  *
1066  *	return of true with *newc unchanged: constraint will always be true.
1067  *
1068  *	return of true with *newc changed: use new constraint in *newc.
1069  *
1070  * the lookup table for all explicit iterators, ex, is passed in.
1071  *
1072  * *newc can either be NULL on entry, or if can contain constraints from
1073  * previous calls to eval_potential() (i.e. for building up an instance
1074  * tree constraint from several potential constraints).  if *newc already
1075  * contains constraints, anything added to it will be joined by adding
1076  * a T_AND node at the top of *newc.
1077  */
1078 int
1079 eval_potential(struct node *np, struct lut *ex, struct node *events[],
1080 	    struct node **newc, struct config *croot)
1081 {
1082 	struct node *newnp;
1083 	struct evalue value;
1084 
1085 	if (eval_expr(np, ex, events, NULL, croot, NULL, 1, &value) == 0) {
1086 		/*
1087 		 * couldn't eval expression because
1088 		 * it contains deferred items.  make
1089 		 * a duplicate expression with all the
1090 		 * non-deferred items expanded.
1091 		 */
1092 		newnp = eval_dup(np, ex, events);
1093 
1094 		if (*newc == NULL) {
1095 			/*
1096 			 * constraint is potentially true if deferred
1097 			 * expression in newnp is true.  *newc was NULL
1098 			 * so new constraint is just the one in newnp.
1099 			 */
1100 			*newc = newnp;
1101 			return (1);
1102 		} else {
1103 			/*
1104 			 * constraint is potentially true if deferred
1105 			 * expression in newnp is true.  *newc already
1106 			 * contained a constraint so add an AND with the
1107 			 * constraint in newnp.
1108 			 */
1109 			*newc = tree_expr(T_AND, *newc, newnp);
1110 			return (1);
1111 		}
1112 	} else if (value.t == UNDEFINED) {
1113 		/* constraint can never be true */
1114 		return (0);
1115 	} else if (value.t == UINT64 && value.v == 0) {
1116 		/* constraint can never be true */
1117 		return (0);
1118 	} else {
1119 		/* constraint is always true (nothing deferred to eval) */
1120 		return (1);
1121 	}
1122 }
1123 
1124 static int
1125 check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype,
1126 		struct node *np)
1127 {
1128 	/* auto-convert T_NAMES to strings */
1129 	if (lp->t == NODEPTR && ((struct node *)(uintptr_t)(lp->v))->t ==
1130 	    T_NAME) {
1131 		char *s = ipath2str(NULL,
1132 		    ipath((struct node *)(uintptr_t)lp->v));
1133 		lp->t = STRING;
1134 		lp->v = (uintptr_t)stable(s);
1135 		FREE(s);
1136 		out(O_ALTFP|O_VERB2, "convert lhs path to \"%s\"",
1137 		    (char *)(uintptr_t)lp->v);
1138 	}
1139 	if (rp != NULL &&
1140 	    rp->t == NODEPTR && ((struct node *)(uintptr_t)(rp->v))->t ==
1141 	    T_NAME) {
1142 		char *s = ipath2str(NULL,
1143 		    ipath((struct node *)(uintptr_t)rp->v));
1144 		rp->t = STRING;
1145 		rp->v = (uintptr_t)stable(s);
1146 		FREE(s);
1147 		out(O_ALTFP|O_VERB2, "convert rhs path to \"%s\"",
1148 		    (char *)(uintptr_t)rp->v);
1149 	}
1150 
1151 	/* auto-convert strings to numbers */
1152 	if (dtype == UINT64) {
1153 		if (lp->t == STRING) {
1154 			lp->t = UINT64;
1155 			lp->v = strtoull((char *)(uintptr_t)lp->v, NULL, 0);
1156 		}
1157 		if (rp != NULL && rp->t == STRING) {
1158 			rp->t = UINT64;
1159 			rp->v = strtoull((char *)(uintptr_t)rp->v, NULL, 0);
1160 		}
1161 	}
1162 
1163 	if (dtype != UNDEFINED && lp->t != dtype) {
1164 		outfl(O_DIE, np->file, np->line,
1165 		    "invalid datatype of argument for operation %s",
1166 		    ptree_nodetype2str(np->t));
1167 		/* NOTREACHED */
1168 		return (1);
1169 	}
1170 
1171 	if (rp != NULL && lp->t != rp->t) {
1172 		outfl(O_DIE, np->file, np->line,
1173 		    "mismatch in datatype of arguments for operation %s",
1174 		    ptree_nodetype2str(np->t));
1175 		/* NOTREACHED */
1176 		return (1);
1177 	}
1178 
1179 	return (0);
1180 }
1181 
1182 /*
1183  * eval_expr -- evaluate expression into *valuep
1184  *
1185  * the meaning of the return value depends on the input value of try.
1186  *
1187  * for try == 1: if any deferred items are encounted, bail out and return
1188  * false.  returns true if we made it through entire expression without
1189  * hitting any deferred items.
1190  *
1191  * for try == 0: return true if all operations were performed successfully.
1192  * return false if otherwise.  for example, any of the following conditions
1193  * will result in a false return value:
1194  *   - attempted use of an uninitialized global variable
1195  *   - failure in function evaluation
1196  *   - illegal arithmetic operation (argument out of range)
1197  */
1198 int
1199 eval_expr(struct node *np, struct lut *ex, struct node *events[],
1200 	struct lut **globals, struct config *croot, struct arrow *arrowp,
1201 	int try, struct evalue *valuep)
1202 {
1203 	struct evalue *gval;
1204 	struct evalue lval;
1205 	struct evalue rval;
1206 
1207 	if (np == NULL) {
1208 		valuep->t = UINT64;
1209 		valuep->v = 1;	/* no constraint means "true" */
1210 		return (1);
1211 	}
1212 
1213 	valuep->t = UNDEFINED;
1214 
1215 	switch (np->t) {
1216 	case T_GLOBID:
1217 		if (try)
1218 			return (0);
1219 
1220 		/*
1221 		 * only handle case of getting (and not setting) the value
1222 		 * of a global variable
1223 		 */
1224 		gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL);
1225 		if (gval == NULL) {
1226 			return (0);
1227 		} else {
1228 			valuep->t = gval->t;
1229 			valuep->v = gval->v;
1230 			return (1);
1231 		}
1232 
1233 	case T_ASSIGN:
1234 		if (try)
1235 			return (0);
1236 
1237 		/*
1238 		 * first evaluate rhs, then try to store value in lhs which
1239 		 * should be a global variable
1240 		 */
1241 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1242 		    arrowp, try, &rval))
1243 			return (0);
1244 
1245 		ASSERT(np->u.expr.left->t == T_GLOBID);
1246 		gval = lut_lookup(*globals,
1247 		    (void *)np->u.expr.left->u.globid.s, NULL);
1248 
1249 		if (gval == NULL) {
1250 			gval = MALLOC(sizeof (*gval));
1251 			*globals = lut_add(*globals,
1252 			    (void *) np->u.expr.left->u.globid.s, gval, NULL);
1253 		}
1254 
1255 		gval->t = rval.t;
1256 		gval->v = rval.v;
1257 
1258 		if (gval->t == UINT64) {
1259 			out(O_ALTFP|O_VERB2,
1260 			    "assign $%s=%llu",
1261 			    np->u.expr.left->u.globid.s, gval->v);
1262 		} else {
1263 			out(O_ALTFP|O_VERB2,
1264 			    "assign $%s=\"%s\"",
1265 			    np->u.expr.left->u.globid.s,
1266 			    (char *)(uintptr_t)gval->v);
1267 		}
1268 
1269 		/*
1270 		 * but always return true -- an assignment should not
1271 		 * cause a constraint to be false.
1272 		 */
1273 		valuep->t = UINT64;
1274 		valuep->v = 1;
1275 		return (1);
1276 
1277 	case T_EQ:
1278 #define	IMPLICIT_ASSIGN_IN_EQ
1279 #ifdef IMPLICIT_ASSIGN_IN_EQ
1280 		/*
1281 		 * if lhs is an uninitialized global variable, perform
1282 		 * an assignment.
1283 		 *
1284 		 * one insidious side effect of implicit assignment is
1285 		 * that the "==" operator does not return a Boolean if
1286 		 * implicit assignment was performed.
1287 		 */
1288 		if (try == 0 &&
1289 		    np->u.expr.left->t == T_GLOBID &&
1290 		    (gval = lut_lookup(*globals,
1291 		    (void *)np->u.expr.left->u.globid.s, NULL)) == NULL) {
1292 			if (!eval_expr(np->u.expr.right, ex, events, globals,
1293 			    croot, arrowp, try, &rval))
1294 				return (0);
1295 
1296 			gval = MALLOC(sizeof (*gval));
1297 			*globals = lut_add(*globals,
1298 			    (void *) np->u.expr.left->u.globid.s,
1299 			    gval, NULL);
1300 
1301 			gval->t = rval.t;
1302 			gval->v = rval.v;
1303 			valuep->t = rval.t;
1304 			valuep->v = rval.v;
1305 			return (1);
1306 		}
1307 #endif  /* IMPLICIT_ASSIGN_IN_EQ */
1308 
1309 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1310 		    arrowp, try, &lval))
1311 			return (0);
1312 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1313 		    arrowp, try, &rval))
1314 			return (0);
1315 		if (rval.t == UINT64 || lval.t == UINT64) {
1316 			if (check_expr_args(&lval, &rval, UINT64, np))
1317 				return (0);
1318 		} else {
1319 			if (check_expr_args(&lval, &rval, UNDEFINED, np))
1320 				return (0);
1321 		}
1322 
1323 		valuep->t = UINT64;
1324 		valuep->v = (lval.v == rval.v);
1325 		return (1);
1326 
1327 	case T_LT:
1328 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1329 		    arrowp, try, &lval))
1330 			return (0);
1331 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1332 		    arrowp, try, &rval))
1333 			return (0);
1334 		if (check_expr_args(&lval, &rval, UINT64, np))
1335 			return (0);
1336 
1337 		valuep->t = UINT64;
1338 		valuep->v = (lval.v < rval.v);
1339 		return (1);
1340 
1341 	case T_LE:
1342 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1343 		    arrowp, try, &lval))
1344 			return (0);
1345 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1346 		    arrowp, try, &rval))
1347 			return (0);
1348 		if (check_expr_args(&lval, &rval, UINT64, np))
1349 			return (0);
1350 
1351 		valuep->t = UINT64;
1352 		valuep->v = (lval.v <= rval.v);
1353 		return (1);
1354 
1355 	case T_GT:
1356 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1357 		    arrowp, try, &lval))
1358 			return (0);
1359 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1360 		    arrowp, try, &rval))
1361 			return (0);
1362 		if (check_expr_args(&lval, &rval, UINT64, np))
1363 			return (0);
1364 
1365 		valuep->t = UINT64;
1366 		valuep->v = (lval.v > rval.v);
1367 		return (1);
1368 
1369 	case T_GE:
1370 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1371 		    arrowp, try, &lval))
1372 			return (0);
1373 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1374 		    arrowp, try, &rval))
1375 			return (0);
1376 		if (check_expr_args(&lval, &rval, UINT64, np))
1377 			return (0);
1378 
1379 		valuep->t = UINT64;
1380 		valuep->v = (lval.v >= rval.v);
1381 		return (1);
1382 
1383 	case T_BITAND:
1384 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1385 		    arrowp, try, &lval))
1386 			return (0);
1387 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1388 		    arrowp, try, &rval))
1389 			return (0);
1390 		if (check_expr_args(&lval, &rval, UINT64, np))
1391 			return (0);
1392 
1393 		valuep->t = lval.t;
1394 		valuep->v = (lval.v & rval.v);
1395 		return (1);
1396 
1397 	case T_BITOR:
1398 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1399 		    arrowp, try, &lval))
1400 			return (0);
1401 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1402 		    arrowp, try, &rval))
1403 			return (0);
1404 		if (check_expr_args(&lval, &rval, UINT64, np))
1405 			return (0);
1406 
1407 		valuep->t = lval.t;
1408 		valuep->v = (lval.v | rval.v);
1409 		return (1);
1410 
1411 	case T_BITXOR:
1412 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1413 		    arrowp, try, &lval))
1414 			return (0);
1415 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1416 		    arrowp, try, &rval))
1417 			return (0);
1418 		if (check_expr_args(&lval, &rval, UINT64, np))
1419 			return (0);
1420 
1421 		valuep->t = lval.t;
1422 		valuep->v = (lval.v ^ rval.v);
1423 		return (1);
1424 
1425 	case T_BITNOT:
1426 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1427 		    arrowp, try, &lval))
1428 			return (0);
1429 		ASSERT(np->u.expr.right == NULL);
1430 		if (check_expr_args(&lval, NULL, UINT64, np))
1431 			return (0);
1432 
1433 		valuep->t = UINT64;
1434 		valuep->v = ~ lval.v;
1435 		return (1);
1436 
1437 	case T_LSHIFT:
1438 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1439 		    arrowp, try, &lval))
1440 			return (0);
1441 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1442 		    arrowp, try, &rval))
1443 			return (0);
1444 		if (check_expr_args(&lval, &rval, UINT64, np))
1445 			return (0);
1446 
1447 		valuep->t = UINT64;
1448 		valuep->v = (lval.v << rval.v);
1449 		return (1);
1450 
1451 	case T_RSHIFT:
1452 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1453 		    arrowp, try, &lval))
1454 			return (0);
1455 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1456 		    arrowp, try, &rval))
1457 			return (0);
1458 		if (check_expr_args(&lval, &rval, UINT64, np))
1459 			return (0);
1460 
1461 		valuep->t = UINT64;
1462 		valuep->v = (lval.v >> rval.v);
1463 		return (1);
1464 
1465 	case T_CONDIF: {
1466 		struct node *retnp;
1467 		int dotrue = 0;
1468 
1469 		/*
1470 		 * evaluate
1471 		 *	expression ? stmtA [ : stmtB ]
1472 		 *
1473 		 * first see if expression is true or false, then determine
1474 		 * if stmtA (or stmtB, if it exists) should be evaluated.
1475 		 *
1476 		 * "dotrue = 1" means stmtA should be evaluated.
1477 		 */
1478 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1479 		    arrowp, try, &lval))
1480 			return (0);
1481 
1482 		if (lval.t != UNDEFINED && lval.v != 0)
1483 			dotrue = 1;
1484 
1485 		ASSERT(np->u.expr.right != NULL);
1486 		if (np->u.expr.right->t == T_CONDELSE) {
1487 			if (dotrue)
1488 				retnp = np->u.expr.right->u.expr.left;
1489 			else
1490 				retnp = np->u.expr.right->u.expr.right;
1491 		} else {
1492 			/* no ELSE clause */
1493 			if (dotrue)
1494 				retnp = np->u.expr.right;
1495 			else {
1496 				outfl(O_DIE, np->file, np->line,
1497 				    "eval_expr: missing condelse");
1498 			}
1499 		}
1500 
1501 		if (!eval_expr(retnp, ex, events, globals, croot,
1502 		    arrowp, try, valuep))
1503 			return (0);
1504 		return (1);
1505 	}
1506 
1507 	case T_CONDELSE:
1508 		/*
1509 		 * shouldn't get here, since T_CONDELSE is supposed to be
1510 		 * evaluated as part of T_CONDIF
1511 		 */
1512 		out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s",
1513 		    ptree_nodetype2str(np->t));
1514 		/*NOTREACHED*/
1515 
1516 	case T_NE:
1517 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1518 		    arrowp, try, &lval))
1519 			return (0);
1520 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1521 		    arrowp, try, &rval))
1522 			return (0);
1523 		if (rval.t == UINT64 || lval.t == UINT64) {
1524 			if (check_expr_args(&lval, &rval, UINT64, np))
1525 				return (0);
1526 		} else {
1527 			if (check_expr_args(&lval, &rval, UNDEFINED, np))
1528 				return (0);
1529 		}
1530 
1531 		valuep->t = UINT64;
1532 		valuep->v = (lval.v != rval.v);
1533 		return (1);
1534 
1535 	case T_LIST:
1536 	case T_AND:
1537 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1538 		    arrowp, try, valuep)) {
1539 			/*
1540 			 * if lhs is unknown, still check rhs. If that
1541 			 * is false we can return false irrespective of lhs
1542 			 */
1543 			if (!try) {
1544 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
1545 				return (0);
1546 			}
1547 			if (!eval_expr(np->u.expr.right, ex, events, globals,
1548 			    croot, arrowp, try, valuep)) {
1549 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
1550 				return (0);
1551 			}
1552 			if (valuep->v != 0) {
1553 				np->u.expr.temp = EXPR_TEMP_LHS_UNK;
1554 				return (0);
1555 			}
1556 		}
1557 		if (valuep->v == 0) {
1558 			valuep->t = UINT64;
1559 			return (1);
1560 		}
1561 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1562 		    arrowp, try, valuep)) {
1563 			np->u.expr.temp = EXPR_TEMP_RHS_UNK;
1564 			return (0);
1565 		}
1566 		valuep->t = UINT64;
1567 		valuep->v = valuep->v == 0 ? 0 : 1;
1568 		return (1);
1569 
1570 	case T_OR:
1571 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1572 		    arrowp, try, valuep)) {
1573 			/*
1574 			 * if lhs is unknown, still check rhs. If that
1575 			 * is true we can return true irrespective of lhs
1576 			 */
1577 			if (!try) {
1578 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
1579 				return (0);
1580 			}
1581 			if (!eval_expr(np->u.expr.right, ex, events, globals,
1582 			    croot, arrowp, try, valuep)) {
1583 				np->u.expr.temp = EXPR_TEMP_BOTH_UNK;
1584 				return (0);
1585 			}
1586 			if (valuep->v == 0) {
1587 				np->u.expr.temp = EXPR_TEMP_LHS_UNK;
1588 				return (0);
1589 			}
1590 		}
1591 		if (valuep->v != 0) {
1592 			valuep->t = UINT64;
1593 			valuep->v = 1;
1594 			return (1);
1595 		}
1596 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1597 		    arrowp, try, valuep)) {
1598 			np->u.expr.temp = EXPR_TEMP_RHS_UNK;
1599 			return (0);
1600 		}
1601 		valuep->t = UINT64;
1602 		valuep->v = valuep->v == 0 ? 0 : 1;
1603 		return (1);
1604 
1605 	case T_NOT:
1606 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1607 		    arrowp, try, valuep))
1608 			return (0);
1609 		valuep->t = UINT64;
1610 		valuep->v = ! valuep->v;
1611 		return (1);
1612 
1613 	case T_ADD:
1614 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1615 		    arrowp, try, &lval))
1616 			return (0);
1617 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1618 		    arrowp, try, &rval))
1619 			return (0);
1620 		if (check_expr_args(&lval, &rval, UINT64, np))
1621 			return (0);
1622 
1623 		valuep->t = lval.t;
1624 		valuep->v = lval.v + rval.v;
1625 		return (1);
1626 
1627 	case T_SUB:
1628 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1629 		    arrowp, try, &lval))
1630 			return (0);
1631 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1632 		    arrowp, try, &rval))
1633 			return (0);
1634 		if (check_expr_args(&lval, &rval, UINT64, np))
1635 			return (0);
1636 
1637 		/* since valuep is unsigned, return false if lval.v < rval.v */
1638 		if (lval.v < rval.v) {
1639 			outfl(O_DIE, np->file, np->line,
1640 			    "eval_expr: T_SUB result is out of range");
1641 		}
1642 
1643 		valuep->t = lval.t;
1644 		valuep->v = lval.v - rval.v;
1645 		return (1);
1646 
1647 	case T_MUL:
1648 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1649 		    arrowp, try, &lval))
1650 			return (0);
1651 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1652 		    arrowp, try, &rval))
1653 			return (0);
1654 		if (check_expr_args(&lval, &rval, UINT64, np))
1655 			return (0);
1656 
1657 		valuep->t = lval.t;
1658 		valuep->v = lval.v * rval.v;
1659 		return (1);
1660 
1661 	case T_DIV:
1662 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1663 		    arrowp, try, &lval))
1664 			return (0);
1665 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1666 		    arrowp, try, &rval))
1667 			return (0);
1668 		if (check_expr_args(&lval, &rval, UINT64, np))
1669 			return (0);
1670 
1671 		/* return false if dividing by zero */
1672 		if (rval.v == 0) {
1673 			outfl(O_DIE, np->file, np->line,
1674 			    "eval_expr: T_DIV division by zero");
1675 		}
1676 
1677 		valuep->t = lval.t;
1678 		valuep->v = lval.v / rval.v;
1679 		return (1);
1680 
1681 	case T_MOD:
1682 		if (!eval_expr(np->u.expr.left, ex, events, globals, croot,
1683 		    arrowp, try, &lval))
1684 			return (0);
1685 		if (!eval_expr(np->u.expr.right, ex, events, globals, croot,
1686 		    arrowp, try, &rval))
1687 			return (0);
1688 		if (check_expr_args(&lval, &rval, UINT64, np))
1689 			return (0);
1690 
1691 		/* return false if dividing by zero */
1692 		if (rval.v == 0) {
1693 			outfl(O_DIE, np->file, np->line,
1694 			    "eval_expr: T_MOD division by zero");
1695 		}
1696 
1697 		valuep->t = lval.t;
1698 		valuep->v = lval.v % rval.v;
1699 		return (1);
1700 
1701 	case T_NAME:
1702 		if (try) {
1703 			struct iterinfo *iterinfop;
1704 			struct node *np1, *np2;
1705 			int i, gotmatch = 0;
1706 
1707 			/*
1708 			 * Check if we have an exact match of the nonwildcarded
1709 			 * path in oldepname - if so we can just use the
1710 			 * full wildcarded path in epname.
1711 			 */
1712 			for (i = 0; i < 1; i++) {
1713 				for (np1 = np,
1714 				    np2 = events[i]->u.event.oldepname;
1715 				    np1 != NULL && np2 != NULL;
1716 				    np1 = np1->u.name.next,
1717 				    np2 = np2->u.name.next) {
1718 					if (strcmp(np1->u.name.s,
1719 					    np2->u.name.s) != 0)
1720 						break;
1721 					if (np1->u.name.child->t !=
1722 					    np2->u.name.child->t)
1723 						break;
1724 					if (np1->u.name.child->t == T_NUM &&
1725 					    np1->u.name.child->u.ull !=
1726 					    np2->u.name.child->u.ull)
1727 						break;
1728 					if (np1->u.name.child->t == T_NAME &&
1729 					    strcmp(np1->u.name.child->u.name.s,
1730 					    np2->u.name.child->u.name.s) != 0)
1731 						break;
1732 					gotmatch++;
1733 				}
1734 				if (np1 == NULL && np2 == NULL) {
1735 					valuep->t = NODEPTR;
1736 					valuep->v = (uintptr_t)
1737 					    events[i]->u.event.epname;
1738 					return (1);
1739 				}
1740 			}
1741 			if (!gotmatch) {
1742 				/*
1743 				 * we're not wildcarding. However at
1744 				 * itree_create() time, we can also expand
1745 				 * simple iterators - so check for those.
1746 				 */
1747 				iterinfop = lut_lookup(ex, (void *)np->u.name.s,
1748 				    NULL);
1749 				if (iterinfop != NULL) {
1750 					valuep->t = UINT64;
1751 					valuep->v =
1752 					    (unsigned long long)iterinfop->num;
1753 					return (1);
1754 				}
1755 			}
1756 			/*
1757 			 * For anything else we'll have to wait for eval_dup().
1758 			 */
1759 			return (0);
1760 		}
1761 
1762 		/* return address of struct node */
1763 		valuep->t = NODEPTR;
1764 		valuep->v = (uintptr_t)np;
1765 		return (1);
1766 
1767 	case T_QUOTE:
1768 		valuep->t = STRING;
1769 		valuep->v = (uintptr_t)np->u.quote.s;
1770 		return (1);
1771 
1772 	case T_FUNC:
1773 		return (eval_func(np, ex, events, np->u.func.arglist,
1774 		    globals, croot, arrowp, try, valuep));
1775 
1776 	case T_NUM:
1777 	case T_TIMEVAL:
1778 		valuep->t = UINT64;
1779 		valuep->v = np->u.ull;
1780 		return (1);
1781 
1782 	default:
1783 		outfl(O_DIE, np->file, np->line,
1784 		    "eval_expr: unexpected node type: %s",
1785 		    ptree_nodetype2str(np->t));
1786 	}
1787 	/*NOTREACHED*/
1788 	return (0);
1789 }
1790 
1791 /*
1792  * eval_fru() and eval_asru() don't do much, but are called from a number
1793  * of places.
1794  */
1795 static struct node *
1796 eval_fru(struct node *np)
1797 {
1798 	ASSERT(np->t == T_NAME);
1799 	return (np);
1800 }
1801 
1802 static struct node *
1803 eval_asru(struct node *np)
1804 {
1805 	ASSERT(np->t == T_NAME);
1806 	return (np);
1807 }
1808