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