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