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