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