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