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
51static struct node *eval_dup(struct node *np, struct lut *ex,
52    struct node *events[]);
53static int check_expr_args(struct evalue *lp, struct evalue *rp,
54    enum datatype dtype, struct node *np);
55static struct node *eval_fru(struct node *np);
56static struct node *eval_asru(struct node *np);
57
58extern 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 */
63static int
64begins_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 */
118static struct node *
119eval_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*/
165static int
166eval_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*/
210static int
211eval_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
949static struct node *
950eval_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 */
1244int
1245eval_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
1290static int
1291check_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 */
1386int
1387eval_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 */
1984static struct node *
1985eval_fru(struct node *np)
1986{
1987	ASSERT(np->t == T_NAME);
1988	return (np);
1989}
1990
1991static struct node *
1992eval_asru(struct node *np)
1993{
1994	ASSERT(np->t == T_NAME);
1995	return (np);
1996}
1997