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