xref: /illumos-gate/usr/src/cmd/fm/modules/common/eversholt/eval.c (revision e2738c5e21a9e5d9a6525e48af4738deda3df455)
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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * eval.c -- constraint evaluation module
27  *
28  * this module evaluates constraints.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include "alloc.h"
38 #include "out.h"
39 #include "stable.h"
40 #include "literals.h"
41 #include "lut.h"
42 #include "tree.h"
43 #include "ptree.h"
44 #include "itree.h"
45 #include "ipath.h"
46 #include "eval.h"
47 #include "config.h"
48 #include "platform.h"
49 #include "fme.h"
50 #include "stats.h"
51 
52 static struct node *eval_dup(struct node *np, struct lut *ex,
53     struct node *epnames[]);
54 static int check_expr_args(struct evalue *lp, struct evalue *rp,
55     enum datatype dtype, struct node *np);
56 
57 /*
58  * begins_with -- return true if rhs path begins with everything in lhs path
59  */
60 static int
61 begins_with(struct node *lhs, struct node *rhs)
62 {
63 	int lnum;
64 	int rnum;
65 
66 	if (lhs == NULL)
67 		return (1);	/* yep -- it all matched */
68 
69 	if (rhs == NULL)
70 		return (0);	/* nope, ran out of rhs first */
71 
72 	ASSERTeq(lhs->t, T_NAME, ptree_nodetype2str);
73 	ASSERTeq(rhs->t, T_NAME, ptree_nodetype2str);
74 
75 	if (lhs->u.name.s != rhs->u.name.s)
76 		return (0);	/* nope, different component names */
77 
78 	if (lhs->u.name.child && lhs->u.name.child->t == T_NUM)
79 		lnum = (int)lhs->u.name.child->u.ull;
80 	else
81 		out(O_DIE, "begins_with: unexpected lhs child");
82 
83 	if (rhs->u.name.child && rhs->u.name.child->t == T_NUM)
84 		rnum = (int)rhs->u.name.child->u.ull;
85 	else
86 		out(O_DIE, "begins_with: unexpected rhs child");
87 
88 	if (lnum != rnum)
89 		return (0);	/* nope, instance numbers were different */
90 
91 	return (begins_with(lhs->u.name.next, rhs->u.name.next));
92 }
93 
94 /*
95  * evaluate a variety of functions and place result in valuep.  return 1 if
96  * function evaluation was successful; 0 if otherwise (e.g., the case of an
97  * invalid argument to the function)
98  */
99 /*ARGSUSED*/
100 static int
101 eval_func(struct node *funcnp, struct lut *ex, struct node *epnames[],
102     struct node *np, struct lut **globals,
103     struct config *croot, struct arrow *arrowp, int try, struct evalue *valuep)
104 {
105 	const char *funcname = funcnp->u.func.s;
106 
107 	if (funcname == L_within) {
108 		/* within()'s are not really constraints -- always true */
109 		valuep->t = UINT64;
110 		valuep->v = 1;
111 		return (1);
112 	} else if (funcname == L_is_under) {
113 		struct node *lhs;
114 		struct node *rhs;
115 
116 		if (np->u.expr.left->t == T_NAME)
117 			lhs = np->u.expr.left;
118 		else if (np->u.expr.left->u.func.s == L_fru)
119 			lhs = eval_fru(np->u.expr.left->u.func.arglist);
120 		else if (np->u.expr.left->u.func.s == L_asru)
121 			lhs = eval_asru(np->u.expr.left->u.func.arglist);
122 		else
123 			out(O_DIE, "is_under: unexpected lhs type: %s",
124 			    ptree_nodetype2str(np->u.expr.left->t));
125 
126 		if (np->u.expr.right->t == T_NAME)
127 			rhs = np->u.expr.right;
128 		else if (np->u.expr.right->u.func.s == L_fru)
129 			rhs = eval_fru(np->u.expr.right->u.func.arglist);
130 		else if (np->u.expr.right->u.func.s == L_asru)
131 			rhs = eval_asru(np->u.expr.right->u.func.arglist);
132 		else
133 			out(O_DIE, "is_under: unexpected rhs type: %s",
134 			    ptree_nodetype2str(np->u.expr.right->t));
135 
136 		/* eval_dup will expand wildcards, iterators, etc... */
137 		lhs = eval_dup(lhs, ex, epnames);
138 		rhs = eval_dup(rhs, ex, epnames);
139 		valuep->t = UINT64;
140 		valuep->v = begins_with(lhs, rhs);
141 
142 		out(O_ALTFP|O_VERB2|O_NONL, "eval_func:is_under(");
143 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, lhs);
144 		out(O_ALTFP|O_VERB2|O_NONL, ",");
145 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, rhs);
146 		out(O_ALTFP|O_VERB2, ") returned %d", (int)valuep->v);
147 
148 		tree_free(lhs);
149 		tree_free(rhs);
150 
151 		return (1);
152 	} else if (funcname == L_confprop) {
153 		struct config *cp;
154 		struct node *lhs;
155 		char *path;
156 		const char *s;
157 
158 		if (np->u.expr.left->u.func.s == L_fru)
159 			lhs = eval_fru(np->u.expr.left->u.func.arglist);
160 		else if (np->u.expr.left->u.func.s == L_asru)
161 			lhs = eval_asru(np->u.expr.left->u.func.arglist);
162 		else
163 			out(O_DIE, "confprop: unexpected lhs type: %s",
164 			    ptree_nodetype2str(np->u.expr.left->t));
165 
166 		/* for now s will point to a quote [see addconfigprop()] */
167 		ASSERT(np->u.expr.right->t == T_QUOTE);
168 
169 		/* eval_dup will expand wildcards, iterators, etc... */
170 		lhs = eval_dup(lhs, ex, epnames);
171 		path = ipath2str(NULL, ipath(lhs));
172 		cp = config_lookup(croot, path, 0);
173 		tree_free(lhs);
174 		FREE((void *)path);
175 		if (cp == NULL)
176 			return (0);
177 		s = config_getprop(cp, np->u.expr.right->u.quote.s);
178 		if (s == NULL)
179 			return (0);
180 		valuep->v = (uintptr_t)stable(s);
181 		valuep->t = STRING;
182 		return (1);
183 	}
184 
185 	if (try)
186 		return (0);
187 
188 	if (funcname == L_fru) {
189 		valuep->t = NODEPTR;
190 		valuep->v = (uintptr_t)eval_fru(np);
191 		return (1);
192 	} else if (funcname == L_asru) {
193 		valuep->t = NODEPTR;
194 		valuep->v = (uintptr_t)eval_asru(np);
195 		return (1);
196 	} else if (funcname == L_defined) {
197 		ASSERTeq(np->t, T_GLOBID, ptree_nodetype2str);
198 		valuep->t = UINT64;
199 		valuep->v = (lut_lookup(*globals,
200 		    (void *)np->u.globid.s, NULL) != NULL);
201 		return (1);
202 	} else if (funcname == L_call) {
203 		return (! platform_call(np, globals, croot, arrowp, valuep));
204 	} else if (funcname == L_is_connected) {
205 		return (! config_is_connected(np, croot, valuep));
206 	} else if (funcname == L_is_on) {
207 		return (! config_is_on(np, croot, valuep));
208 	} else if (funcname == L_is_present) {
209 		return (! config_is_present(np, croot, valuep));
210 	} else if (funcname == L_is_type) {
211 		return (! config_is_type(np, croot, valuep));
212 	} else if (funcname == L_envprop) {
213 		outfl(O_DIE, np->file, np->line,
214 		    "eval_func: %s not yet supported", funcname);
215 	} else if (funcname == L_payloadprop) {
216 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
217 		    "payloadprop(\"%s\") ", np->u.quote.s);
218 
219 		if (platform_payloadprop(np, valuep)) {
220 			/* platform_payloadprop() returned false */
221 			out(O_ALTFP|O_VERB2, "not found.");
222 			return (0);
223 		} else {
224 			switch (valuep->t) {
225 			case UINT64:
226 			case NODEPTR:
227 				out(O_ALTFP|O_VERB2, "found: %llu", valuep->v);
228 				break;
229 			case STRING:
230 				out(O_ALTFP|O_VERB2, "found: \"%s\"",
231 				    (char *)(uintptr_t)valuep->v);
232 				break;
233 			default:
234 				out(O_ALTFP|O_VERB2, "found: undefined");
235 				break;
236 			}
237 			return (1);
238 		}
239 	} else if (funcname == L_setpayloadprop) {
240 		struct evalue *payloadvalp;
241 
242 		ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t));
243 		ASSERTinfo(np->u.expr.left->t == T_QUOTE,
244 		    ptree_nodetype2str(np->u.expr.left->t));
245 
246 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
247 		    "setpayloadprop: %s: %s=",
248 		    arrowp->tail->myevent->enode->u.event.ename->u.name.s,
249 		    np->u.expr.left->u.quote.s);
250 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right);
251 
252 		/*
253 		 * allocate a struct evalue to hold the payload property's
254 		 * value, unless we've been here already, in which case we
255 		 * might calculate a different value, but we'll store it
256 		 * in the already-allocated struct evalue.
257 		 */
258 		if ((payloadvalp = (struct evalue *)lut_lookup(
259 		    arrowp->tail->myevent->payloadprops,
260 		    (void *)np->u.expr.left->u.quote.s, NULL)) == NULL) {
261 			payloadvalp = MALLOC(sizeof (*payloadvalp));
262 		}
263 
264 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
265 		    arrowp, try, payloadvalp)) {
266 			out(O_ALTFP|O_VERB2, " (cannot eval, using zero)");
267 			payloadvalp->t = UINT64;
268 			payloadvalp->v = 0;
269 		} else {
270 			if (payloadvalp->t == UINT64)
271 				out(O_ALTFP|O_VERB2,
272 				    " (%llu)", payloadvalp->v);
273 			else
274 				out(O_ALTFP|O_VERB2, " (\"%s\")",
275 				    (char *)(uintptr_t)payloadvalp->v);
276 		}
277 
278 		/* add to table of payload properties for current problem */
279 		arrowp->tail->myevent->payloadprops =
280 		    lut_add(arrowp->tail->myevent->payloadprops,
281 		    (void *)np->u.expr.left->u.quote.s,
282 		    (void *)payloadvalp, NULL);
283 
284 		/* function is always true */
285 		valuep->t = UINT64;
286 		valuep->v = 1;
287 		return (1);
288 	} else if (funcname == L_payloadprop_defined) {
289 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
290 		    "payloadprop_defined(\"%s\") ", np->u.quote.s);
291 
292 		if (platform_payloadprop(np, NULL)) {
293 			/* platform_payloadprop() returned false */
294 			valuep->v = 0;
295 			out(O_ALTFP|O_VERB2, "not found.");
296 		} else {
297 			valuep->v = 1;
298 			out(O_ALTFP|O_VERB2, "found.");
299 		}
300 		valuep->t = UINT64;
301 		return (1);
302 	} else if (funcname == L_payloadprop_contains) {
303 		int nvals;
304 		struct evalue *vals;
305 		struct evalue cmpval;
306 
307 		ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t));
308 		ASSERTinfo(np->u.expr.left->t == T_QUOTE,
309 		    ptree_nodetype2str(np->u.expr.left->t));
310 
311 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
312 		    "payloadprop_contains(\"%s\", ",
313 		    np->u.expr.left->u.quote.s);
314 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right);
315 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, ") ");
316 
317 		/* evaluate the expression we're comparing against */
318 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
319 		    arrowp, try, &cmpval)) {
320 			out(O_ALTFP|O_VERB2|O_NONL,
321 			    "(cannot eval, using zero) ");
322 			cmpval.t = UINT64;
323 			cmpval.v = 0;
324 		} else {
325 			if (cmpval.t == UINT64)
326 				out(O_ALTFP|O_VERB2,
327 				    "(%llu) ", cmpval.v);
328 			else
329 				out(O_ALTFP|O_VERB2,
330 				    "(\"%s\") ", (char *)(uintptr_t)cmpval.v);
331 		}
332 
333 		/* get the payload values and check for a match */
334 		vals = platform_payloadprop_values(np->u.expr.left->u.quote.s,
335 		    &nvals);
336 		valuep->t = UINT64;
337 		valuep->v = 0;
338 		if (nvals == 0) {
339 			out(O_ALTFP|O_VERB2, "not found.");
340 		} else {
341 			struct evalue preval;
342 			int i;
343 
344 			out(O_ALTFP|O_VERB2|O_NONL, "found %d values ", nvals);
345 
346 			for (i = 0; i < nvals; i++) {
347 
348 				preval.t = vals[i].t;
349 				preval.v = vals[i].v;
350 
351 				if (check_expr_args(&vals[i], &cmpval,
352 				    UNDEFINED, np))
353 					continue;
354 
355 				/*
356 				 * If we auto-converted the value to a
357 				 * string, we need to free the
358 				 * original tree value.
359 				 */
360 				if (preval.t == NODEPTR &&
361 				    ((struct node *)(uintptr_t)(preval.v))->t ==
362 				    T_NAME) {
363 					tree_free((struct node *)(uintptr_t)
364 					    preval.v);
365 				}
366 
367 				if (vals[i].v == cmpval.v) {
368 					valuep->v = 1;
369 					break;
370 				}
371 			}
372 
373 			if (valuep->v)
374 				out(O_ALTFP|O_VERB2, "match.");
375 			else
376 				out(O_ALTFP|O_VERB2, "no match.");
377 
378 			for (i = 0; i < nvals; i++) {
379 				if (vals[i].t == NODEPTR) {
380 					tree_free((struct node *)(uintptr_t)
381 					    vals[i].v);
382 					break;
383 				}
384 			}
385 			FREE(vals);
386 		}
387 		return (1);
388 	} else if (funcname == L_confcall) {
389 		return (!platform_confcall(np, globals, croot, arrowp, valuep));
390 	} else if (funcname == L_count) {
391 		struct stats *statp;
392 		struct istat_entry ent;
393 
394 		ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t));
395 
396 		ent.ename = np->u.event.ename->u.name.s;
397 		ent.ipath = ipath(np->u.event.epname);
398 
399 		valuep->t = UINT64;
400 		if ((statp = (struct stats *)
401 		    lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL)
402 			valuep->v = 0;
403 		else
404 			valuep->v = stats_counter_value(statp);
405 
406 		return (1);
407 	} else
408 		outfl(O_DIE, np->file, np->line,
409 		    "eval_func: unexpected func: %s", funcname);
410 	/*NOTREACHED*/
411 	return (0);
412 }
413 
414 static struct node *
415 eval_wildcardedname(struct node *np, struct lut *ex, struct node *epnames[])
416 {
417 	struct node *npstart, *npend, *npref, *newnp;
418 	struct node *np1, *np2, *retp;
419 	int i;
420 
421 	if (epnames == NULL || epnames[0] == NULL)
422 		return (NULL);
423 
424 	for (i = 0; epnames[i] != NULL; i++) {
425 		if (tree_namecmp(np, epnames[i]) == 0)
426 			return (NULL);
427 	}
428 
429 	/*
430 	 * get to this point if np does not match any of the entries in
431 	 * epnames.  check if np is a path that must preceded by a wildcard
432 	 * portion.  for this case we must first determine which epnames[]
433 	 * entry should be used for wildcarding.
434 	 */
435 	npstart = NULL;
436 	for (i = 0; epnames[i] != NULL; i++) {
437 		for (npref = epnames[i]; npref; npref = npref->u.name.next) {
438 			if (npref->u.name.s == np->u.name.s) {
439 				for (np1 = npref, np2 = np;
440 				    np1 != NULL && np2 != NULL;
441 				    np1 = np1->u.name.next,
442 					    np2 = np2->u.name.next) {
443 					if (np1->u.name.s != np2->u.name.s)
444 						break;
445 				}
446 				if (np2 == NULL) {
447 					npstart = epnames[i];
448 					npend = npref;
449 					if (np1 == NULL)
450 						break;
451 				}
452 			}
453 		}
454 
455 		if (npstart != NULL)
456 			break;
457 	}
458 
459 	if (npstart == NULL) {
460 		/* no match; np is not a path to be wildcarded */
461 		return (NULL);
462 	}
463 
464 	/*
465 	 * dup (npstart -- npend) which is the wildcarded portion.  all
466 	 * children should be T_NUMs.
467 	 */
468 	retp = NULL;
469 	for (npref = npstart;
470 	    ! (npref == NULL || npref == npend);
471 	    npref = npref->u.name.next) {
472 		newnp = newnode(T_NAME, np->file, np->line);
473 
474 		newnp->u.name.t = npref->u.name.t;
475 		newnp->u.name.s = npref->u.name.s;
476 		newnp->u.name.last = newnp;
477 		newnp->u.name.it = npref->u.name.it;
478 		newnp->u.name.cp = npref->u.name.cp;
479 
480 		ASSERT(npref->u.name.child != NULL);
481 		ASSERT(npref->u.name.child->t == T_NUM);
482 		newnp->u.name.child = newnode(T_NUM, np->file, np->line);
483 		newnp->u.name.child->u.ull = npref->u.name.child->u.ull;
484 
485 		if (retp == NULL) {
486 			retp = newnp;
487 		} else {
488 			retp->u.name.last->u.name.next = newnp;
489 			retp->u.name.last = newnp;
490 		}
491 	}
492 
493 	ASSERT(retp != NULL);
494 
495 	/* now append the nonwildcarded portion */
496 	retp = tree_name_append(retp, eval_dup(np, ex, NULL));
497 
498 	return (retp);
499 }
500 
501 static struct node *
502 eval_dup(struct node *np, struct lut *ex, struct node *epnames[])
503 {
504 	struct node *newnp;
505 
506 	if (np == NULL)
507 		return (NULL);
508 
509 	switch (np->t) {
510 	case T_GLOBID:
511 		return (tree_globid(np->u.globid.s, np->file, np->line));
512 
513 	case T_ASSIGN:
514 	case T_CONDIF:
515 	case T_CONDELSE:
516 	case T_NE:
517 	case T_EQ:
518 	case T_LT:
519 	case T_LE:
520 	case T_GT:
521 	case T_GE:
522 	case T_BITAND:
523 	case T_BITOR:
524 	case T_BITXOR:
525 	case T_BITNOT:
526 	case T_LSHIFT:
527 	case T_RSHIFT:
528 	case T_LIST:
529 	case T_AND:
530 	case T_OR:
531 	case T_NOT:
532 	case T_ADD:
533 	case T_SUB:
534 	case T_MUL:
535 	case T_DIV:
536 	case T_MOD:
537 		return (tree_expr(np->t,
538 				    eval_dup(np->u.expr.left, ex, epnames),
539 				    eval_dup(np->u.expr.right, ex, epnames)));
540 
541 	case T_NAME: {
542 		struct iterinfo *iterinfop;
543 		struct node *newchild = NULL;
544 
545 		iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
546 		if (iterinfop != NULL) {
547 			/* explicit iterator; not part of pathname */
548 			newnp = newnode(T_NUM, np->file, np->line);
549 			newnp->u.ull = iterinfop->num;
550 			return (newnp);
551 		}
552 
553 		/* see if np is a path with wildcard portion */
554 		newnp = eval_wildcardedname(np, ex, epnames);
555 		if (newnp != NULL)
556 			return (newnp);
557 
558 		/* turn off wildcarding for child */
559 		newchild = eval_dup(np->u.name.child, ex, NULL);
560 
561 		if (newchild != NULL) {
562 			if (newchild->t != T_NUM) {
563 				/*
564 				 * not a number, eh?  we must resolve this
565 				 * to a number.
566 				 */
567 				struct evalue value;
568 
569 				if (eval_expr(newchild, ex, epnames,
570 				    NULL, NULL, NULL, 1, &value) == 0 ||
571 				    value.t != UINT64) {
572 					outfl(O_DIE, np->file, np->line,
573 					    "eval_dup: could not resolve "
574 					    "iterator of %s", np->u.name.s);
575 				}
576 
577 				tree_free(newchild);
578 				newchild = newnode(T_NUM, np->file, np->line);
579 				newchild->u.ull = value.v;
580 			}
581 
582 			newnp = newnode(np->t, np->file, np->line);
583 			newnp->u.name.s = np->u.name.s;
584 			newnp->u.name.it = np->u.name.it;
585 			newnp->u.name.cp = np->u.name.cp;
586 
587 			newnp->u.name.last = newnp;
588 			newnp->u.name.child = newchild;
589 
590 			if (np->u.name.next != NULL) {
591 				/* turn off wildcarding for next */
592 				return (tree_name_append(newnp,
593 					eval_dup(np->u.name.next, ex, NULL)));
594 			} else {
595 				return (newnp);
596 			}
597 		} else {
598 			outfl(O_DIE, np->file, np->line,
599 			    "eval_dup: internal error: \"%s\" is neither "
600 			    "an iterator nor a pathname", np->u.name.s);
601 		}
602 		/*NOTREACHED*/
603 		break;
604 	}
605 
606 	case T_EVENT:
607 		newnp = newnode(T_NAME, np->file, np->line);
608 
609 		newnp->u.name.t = np->u.event.ename->u.name.t;
610 		newnp->u.name.s = np->u.event.ename->u.name.s;
611 		newnp->u.name.it = np->u.event.ename->u.name.it;
612 		newnp->u.name.last = newnp;
613 
614 		return (tree_event(newnp,
615 		    eval_dup(np->u.event.epname, ex, epnames),
616 		    eval_dup(np->u.event.eexprlist, ex, epnames)));
617 
618 	case T_FUNC:
619 		return (tree_func(np->u.func.s,
620 		    eval_dup(np->u.func.arglist, ex, epnames),
621 		    np->file, np->line));
622 
623 	case T_QUOTE:
624 		newnp = newnode(T_QUOTE, np->file, np->line);
625 		newnp->u.quote.s = np->u.quote.s;
626 		return (newnp);
627 
628 	case T_NUM:
629 		newnp = newnode(T_NUM, np->file, np->line);
630 		newnp->u.ull = np->u.ull;
631 		return (newnp);
632 
633 	default:
634 		outfl(O_DIE, np->file, np->line,
635 		    "eval_dup: unexpected node type: %s",
636 		    ptree_nodetype2str(np->t));
637 	}
638 	/*NOTREACHED*/
639 	return (0);
640 }
641 
642 /*
643  * eval_potential -- see if constraint is potentially true
644  *
645  * this function is used at instance tree creation time to see if
646  * any constraints are already known to be false.  if this function
647  * returns false, then the constraint will always be false and there's
648  * no need to include the propagation arrow in the instance tree.
649  *
650  * if this routine returns true, either the constraint is known to
651  * be always true (so there's no point in attaching the constraint
652  * to the propagation arrow in the instance tree), or the constraint
653  * contains "deferred" expressions like global variables or poller calls
654  * and so it must be evaluated during calls to fme_eval().  in this last
655  * case, where a constraint needs to be attached to the propagation arrow
656  * in the instance tree, this routine returns a newly created constraint
657  * in *newc where all the non-deferred things have been filled in.
658  *
659  * so in summary:
660  *
661  *	return of false: constraint can never be true, *newc will be NULL.
662  *
663  *	return of true with *newc unchanged: constraint will always be true.
664  *
665  *	return of true with *newc changed: use new constraint in *newc.
666  *
667  * the lookup table for all explicit iterators, ex, is passed in.
668  *
669  * *newc can either be NULL on entry, or if can contain constraints from
670  * previous calls to eval_potential() (i.e. for building up an instance
671  * tree constraint from several potential constraints).  if *newc already
672  * contains constraints, anything added to it will be joined by adding
673  * a T_AND node at the top of *newc.
674  */
675 int
676 eval_potential(struct node *np, struct lut *ex, struct node *epnames[],
677 	    struct node **newc, struct config *croot)
678 {
679 	struct node *newnp;
680 	struct evalue value;
681 
682 	if (eval_expr(np, ex, epnames, NULL, croot, NULL, 1, &value) == 0) {
683 		/*
684 		 * couldn't eval expression because
685 		 * it contains deferred items.  make
686 		 * a duplicate expression with all the
687 		 * non-deferred items expanded.
688 		 */
689 		newnp = eval_dup(np, ex, epnames);
690 
691 		if (*newc == NULL) {
692 			/*
693 			 * constraint is potentially true if deferred
694 			 * expression in newnp is true.  *newc was NULL
695 			 * so new constraint is just the one in newnp.
696 			 */
697 			*newc = newnp;
698 			return (1);
699 		} else {
700 			/*
701 			 * constraint is potentially true if deferred
702 			 * expression in newnp is true.  *newc already
703 			 * contained a constraint so add an AND with the
704 			 * constraint in newnp.
705 			 */
706 			*newc = tree_expr(T_AND, *newc, newnp);
707 			return (1);
708 		}
709 	} else if (value.t == UNDEFINED) {
710 		/* constraint can never be true */
711 		return (0);
712 	} else if (value.t == UINT64 && value.v == 0) {
713 		/* constraint can never be true */
714 		return (0);
715 	} else {
716 		/* constraint is always true (nothing deferred to eval) */
717 		return (1);
718 	}
719 }
720 
721 static int
722 check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype,
723 		struct node *np)
724 {
725 	/* auto-convert T_NAMES to strings */
726 	if (lp->t == NODEPTR && ((struct node *)(uintptr_t)(lp->v))->t ==
727 	    T_NAME) {
728 		char *s = ipath2str(NULL,
729 		    ipath((struct node *)(uintptr_t)lp->v));
730 		lp->t = STRING;
731 		lp->v = (uintptr_t)stable(s);
732 		FREE(s);
733 		out(O_ALTFP|O_VERB2, "convert lhs path to \"%s\"",
734 		    (char *)(uintptr_t)lp->v);
735 	}
736 	if (rp != NULL &&
737 	    rp->t == NODEPTR && ((struct node *)(uintptr_t)(rp->v))->t ==
738 	    T_NAME) {
739 		char *s = ipath2str(NULL,
740 		    ipath((struct node *)(uintptr_t)rp->v));
741 		rp->t = STRING;
742 		rp->v = (uintptr_t)stable(s);
743 		FREE(s);
744 		out(O_ALTFP|O_VERB2, "convert rhs path to \"%s\"",
745 		    (char *)(uintptr_t)rp->v);
746 	}
747 
748 	/* auto-convert strings to numbers */
749 	if (dtype == UINT64) {
750 		if (lp->t == STRING) {
751 			lp->t = UINT64;
752 			lp->v = strtoull((char *)(uintptr_t)lp->v, NULL, 0);
753 		}
754 		if (rp != NULL && rp->t == STRING) {
755 			rp->t = UINT64;
756 			rp->v = strtoull((char *)(uintptr_t)rp->v, NULL, 0);
757 		}
758 	}
759 
760 	if (dtype != UNDEFINED && lp->t != dtype) {
761 		outfl(O_OK, np->file, np->line,
762 			"invalid datatype of argument for operation %s",
763 			ptree_nodetype2str(np->t));
764 		return (1);
765 	}
766 
767 	if (rp != NULL && lp->t != rp->t) {
768 		outfl(O_OK, np->file, np->line,
769 			"mismatch in datatype of arguments for operation %s",
770 			ptree_nodetype2str(np->t));
771 		return (1);
772 	}
773 
774 	return (0);
775 }
776 
777 /*
778  * eval_expr -- evaluate expression into *valuep
779  *
780  * the meaning of the return value depends on the input value of try.
781  *
782  * for try == 1: if any deferred items are encounted, bail out and return
783  * false.  returns true if we made it through entire expression without
784  * hitting any deferred items.
785  *
786  * for try == 0: return true if all operations were performed successfully.
787  * return false if otherwise.  for example, any of the following conditions
788  * will result in a false return value:
789  *   - attempted use of an uninitialized global variable
790  *   - failure in function evaluation
791  *   - illegal arithmetic operation (argument out of range)
792  */
793 int
794 eval_expr(struct node *np, struct lut *ex, struct node *epnames[],
795 	struct lut **globals, struct config *croot, struct arrow *arrowp,
796 	int try, struct evalue *valuep)
797 {
798 	struct evalue *gval;
799 	struct evalue lval;
800 	struct evalue rval;
801 
802 	if (np == NULL) {
803 		valuep->t = UINT64;
804 		valuep->v = 1;	/* no constraint means "true" */
805 		return (1);
806 	}
807 
808 	valuep->t = UNDEFINED;
809 
810 	switch (np->t) {
811 	case T_GLOBID:
812 		if (try)
813 			return (0);
814 
815 		/*
816 		 * only handle case of getting (and not setting) the value
817 		 * of a global variable
818 		 */
819 		gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL);
820 		if (gval == NULL) {
821 			valuep->t = UNDEFINED;
822 			return (0);
823 		} else {
824 			valuep->t = gval->t;
825 			valuep->v = gval->v;
826 			return (1);
827 		}
828 
829 	case T_ASSIGN:
830 		if (try)
831 			return (0);
832 
833 		/*
834 		 * first evaluate rhs, then try to store value in lhs which
835 		 * should be a global variable
836 		 */
837 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
838 			    arrowp, try, &rval))
839 			return (0);
840 
841 		ASSERT(np->u.expr.left->t == T_GLOBID);
842 		gval = lut_lookup(*globals,
843 				(void *)np->u.expr.left->u.globid.s, NULL);
844 
845 		if (gval == NULL) {
846 			gval = MALLOC(sizeof (*gval));
847 			*globals = lut_add(*globals,
848 					(void *) np->u.expr.left->u.globid.s,
849 					gval, NULL);
850 		}
851 
852 		gval->t = rval.t;
853 		gval->v = rval.v;
854 
855 		if (gval->t == UINT64) {
856 			out(O_ALTFP|O_VERB2,
857 			    "assign $%s=%llu",
858 			    np->u.expr.left->u.globid.s, gval->v);
859 		} else {
860 			out(O_ALTFP|O_VERB2,
861 			    "assign $%s=\"%s\"",
862 			    np->u.expr.left->u.globid.s,
863 			    (char *)(uintptr_t)gval->v);
864 		}
865 
866 		/*
867 		 * but always return true -- an assignment should not
868 		 * cause a constraint to be false.
869 		 */
870 		valuep->t = UINT64;
871 		valuep->v = 1;
872 		return (1);
873 
874 	case T_EQ:
875 #define	IMPLICIT_ASSIGN_IN_EQ
876 #ifdef IMPLICIT_ASSIGN_IN_EQ
877 		/*
878 		 * if lhs is an uninitialized global variable, perform
879 		 * an assignment.
880 		 *
881 		 * one insidious side effect of implicit assignment is
882 		 * that the "==" operator does not return a Boolean if
883 		 * implicit assignment was performed.
884 		 */
885 		if (try == 0 &&
886 		    np->u.expr.left->t == T_GLOBID &&
887 		    (gval = lut_lookup(*globals,
888 			(void *)np->u.expr.left->u.globid.s, NULL)) == NULL) {
889 			if (!eval_expr(np->u.expr.right, ex, epnames, globals,
890 					croot, arrowp, try, &rval))
891 				return (0);
892 
893 			gval = MALLOC(sizeof (*gval));
894 			*globals = lut_add(*globals,
895 					(void *) np->u.expr.left->u.globid.s,
896 					gval, NULL);
897 
898 			gval->t = rval.t;
899 			gval->v = rval.v;
900 			valuep->t = rval.t;
901 			valuep->v = rval.v;
902 			return (1);
903 		}
904 #endif  /* IMPLICIT_ASSIGN_IN_EQ */
905 
906 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
907 				arrowp, try, &lval))
908 			return (0);
909 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
910 				arrowp, try, &rval))
911 			return (0);
912 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
913 			return (0);
914 
915 		valuep->t = UINT64;
916 		valuep->v = (lval.v == rval.v);
917 		return (1);
918 
919 	case T_LT:
920 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
921 				arrowp, try, &lval))
922 			return (0);
923 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
924 				arrowp, try, &rval))
925 			return (0);
926 		if (check_expr_args(&lval, &rval, UINT64, np))
927 			return (0);
928 
929 		valuep->t = UINT64;
930 		valuep->v = (lval.v < rval.v);
931 		return (1);
932 
933 	case T_LE:
934 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
935 				arrowp, try, &lval))
936 			return (0);
937 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
938 				arrowp, try, &rval))
939 			return (0);
940 		if (check_expr_args(&lval, &rval, UINT64, np))
941 			return (0);
942 
943 		valuep->t = UINT64;
944 		valuep->v = (lval.v <= rval.v);
945 		return (1);
946 
947 	case T_GT:
948 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
949 				arrowp, try, &lval))
950 			return (0);
951 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
952 				arrowp, try, &rval))
953 			return (0);
954 		if (check_expr_args(&lval, &rval, UINT64, np))
955 			return (0);
956 
957 		valuep->t = UINT64;
958 		valuep->v = (lval.v > rval.v);
959 		return (1);
960 
961 	case T_GE:
962 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
963 				arrowp, try, &lval))
964 			return (0);
965 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
966 				arrowp, try, &rval))
967 			return (0);
968 		if (check_expr_args(&lval, &rval, UINT64, np))
969 			return (0);
970 
971 		valuep->t = UINT64;
972 		valuep->v = (lval.v >= rval.v);
973 		return (1);
974 
975 	case T_BITAND:
976 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
977 				arrowp, try, &lval))
978 			return (0);
979 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
980 				arrowp, try, &rval))
981 			return (0);
982 		if (check_expr_args(&lval, &rval, UINT64, np))
983 			return (0);
984 
985 		valuep->t = lval.t;
986 		valuep->v = (lval.v & rval.v);
987 		return (1);
988 
989 	case T_BITOR:
990 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
991 				arrowp, try, &lval))
992 			return (0);
993 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
994 				arrowp, try, &rval))
995 			return (0);
996 		if (check_expr_args(&lval, &rval, UINT64, np))
997 			return (0);
998 
999 		valuep->t = lval.t;
1000 		valuep->v = (lval.v | rval.v);
1001 		return (1);
1002 
1003 	case T_BITXOR:
1004 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1005 				arrowp, try, &lval))
1006 			return (0);
1007 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1008 				arrowp, try, &rval))
1009 			return (0);
1010 		if (check_expr_args(&lval, &rval, UINT64, np))
1011 			return (0);
1012 
1013 		valuep->t = lval.t;
1014 		valuep->v = (lval.v ^ rval.v);
1015 		return (1);
1016 
1017 	case T_BITNOT:
1018 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1019 				arrowp, try, &lval))
1020 			return (0);
1021 		ASSERT(np->u.expr.right == NULL);
1022 		if (check_expr_args(&lval, NULL, UINT64, np))
1023 			return (0);
1024 
1025 		valuep->t = UINT64;
1026 		valuep->v = ~ lval.v;
1027 		return (1);
1028 
1029 	case T_LSHIFT:
1030 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1031 				arrowp, try, &lval))
1032 			return (0);
1033 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1034 				arrowp, try, &rval))
1035 			return (0);
1036 		if (check_expr_args(&lval, &rval, UINT64, np))
1037 			return (0);
1038 
1039 		valuep->t = UINT64;
1040 		valuep->v = (lval.v << rval.v);
1041 		return (1);
1042 
1043 	case T_RSHIFT:
1044 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1045 				arrowp, try, &lval))
1046 			return (0);
1047 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1048 				arrowp, try, &rval))
1049 			return (0);
1050 		if (check_expr_args(&lval, &rval, UINT64, np))
1051 			return (0);
1052 
1053 		valuep->t = UINT64;
1054 		valuep->v = (lval.v >> rval.v);
1055 		return (1);
1056 
1057 	case T_CONDIF: {
1058 		struct node *retnp;
1059 		int dotrue = 0;
1060 
1061 		/*
1062 		 * evaluate
1063 		 *	expression ? stmtA [ : stmtB ]
1064 		 *
1065 		 * first see if expression is true or false, then determine
1066 		 * if stmtA (or stmtB, if it exists) should be evaluated.
1067 		 *
1068 		 * "dotrue = 1" means stmtA should be evaluated.
1069 		 */
1070 		if (eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1071 				arrowp, try, &lval) &&
1072 		    lval.t != UNDEFINED && lval.v != 0)
1073 			dotrue = 1;
1074 
1075 		ASSERT(np->u.expr.right != NULL);
1076 		if (np->u.expr.right->t == T_CONDELSE) {
1077 			if (dotrue)
1078 				retnp = np->u.expr.right->u.expr.left;
1079 			else
1080 				retnp = np->u.expr.right->u.expr.right;
1081 		} else {
1082 			/* no ELSE clause */
1083 			if (dotrue)
1084 				retnp = np->u.expr.right;
1085 			else {
1086 				valuep->t = UINT64;
1087 				valuep->v = 0;
1088 				return (0);
1089 			}
1090 		}
1091 
1092 		if (!eval_expr(retnp, ex, epnames, globals, croot,
1093 			    arrowp, try, valuep))
1094 			return (0);
1095 		return (1);
1096 	}
1097 
1098 	case T_CONDELSE:
1099 		/*
1100 		 * shouldn't get here, since T_CONDELSE is supposed to be
1101 		 * evaluated as part of T_CONDIF
1102 		 */
1103 		out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s",
1104 		    ptree_nodetype2str(np->t));
1105 		return (0);
1106 
1107 	case T_NE:
1108 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1109 				arrowp, try, &lval))
1110 			return (0);
1111 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1112 				arrowp, try, &rval))
1113 			return (0);
1114 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
1115 			return (0);
1116 
1117 		valuep->t = UINT64;
1118 		valuep->v = (lval.v != rval.v);
1119 		return (1);
1120 
1121 	case T_LIST:
1122 	case T_AND:
1123 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1124 				arrowp, try, valuep))
1125 			return (0);
1126 		if (valuep->v == 0) {
1127 			valuep->t = UINT64;
1128 			return (1);
1129 		}
1130 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1131 				arrowp, try, valuep))
1132 			return (0);
1133 		valuep->t = UINT64;
1134 		valuep->v = valuep->v == 0 ? 0 : 1;
1135 		return (1);
1136 
1137 	case T_OR:
1138 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1139 				arrowp, try, valuep))
1140 			return (0);
1141 		if (valuep->v != 0) {
1142 			valuep->t = UINT64;
1143 			valuep->v = 1;
1144 			return (1);
1145 		}
1146 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1147 				arrowp, try, valuep))
1148 			return (0);
1149 		valuep->t = UINT64;
1150 		valuep->v = valuep->v == 0 ? 0 : 1;
1151 		return (1);
1152 
1153 	case T_NOT:
1154 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1155 				arrowp, try, valuep))
1156 			return (0);
1157 		valuep->t = UINT64;
1158 		valuep->v = ! valuep->v;
1159 		return (1);
1160 
1161 	case T_ADD:
1162 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1163 				arrowp, try, &lval))
1164 			return (0);
1165 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1166 				arrowp, try, &rval))
1167 			return (0);
1168 		if (check_expr_args(&lval, &rval, UINT64, np))
1169 			return (0);
1170 
1171 		valuep->t = lval.t;
1172 		valuep->v = lval.v + rval.v;
1173 		return (1);
1174 
1175 	case T_SUB:
1176 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1177 				arrowp, try, &lval))
1178 			return (0);
1179 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1180 				arrowp, try, &rval))
1181 			return (0);
1182 		if (check_expr_args(&lval, &rval, UINT64, np))
1183 			return (0);
1184 
1185 		/* since valuep is unsigned, return false if lval.v < rval.v */
1186 		if (lval.v < rval.v) {
1187 			out(O_ERR, "eval_expr: T_SUB result is out of range");
1188 			valuep->t = UNDEFINED;
1189 			return (0);
1190 		}
1191 
1192 		valuep->t = lval.t;
1193 		valuep->v = lval.v - rval.v;
1194 		return (1);
1195 
1196 	case T_MUL:
1197 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1198 				arrowp, try, &lval))
1199 			return (0);
1200 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1201 				arrowp, try, &rval))
1202 			return (0);
1203 		if (check_expr_args(&lval, &rval, UINT64, np))
1204 			return (0);
1205 
1206 		valuep->t = lval.t;
1207 		valuep->v = lval.v * rval.v;
1208 		return (1);
1209 
1210 	case T_DIV:
1211 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1212 				arrowp, try, &lval))
1213 			return (0);
1214 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1215 				arrowp, try, &rval))
1216 			return (0);
1217 		if (check_expr_args(&lval, &rval, UINT64, np))
1218 			return (0);
1219 
1220 		/* return false if dividing by zero */
1221 		if (rval.v == 0) {
1222 			out(O_ERR, "eval_expr: T_DIV division by zero");
1223 			valuep->t = UNDEFINED;
1224 			return (0);
1225 		}
1226 
1227 		valuep->t = lval.t;
1228 		valuep->v = lval.v / rval.v;
1229 		return (1);
1230 
1231 	case T_MOD:
1232 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1233 				arrowp, try, &lval))
1234 			return (0);
1235 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1236 				arrowp, try, &rval))
1237 			return (0);
1238 		if (check_expr_args(&lval, &rval, UINT64, np))
1239 			return (0);
1240 
1241 		/* return false if dividing by zero */
1242 		if (rval.v == 0) {
1243 			out(O_ERR, "eval_expr: T_MOD division by zero");
1244 			valuep->t = UNDEFINED;
1245 			return (0);
1246 		}
1247 
1248 		valuep->t = lval.t;
1249 		valuep->v = lval.v % rval.v;
1250 		return (1);
1251 
1252 	case T_NAME:
1253 		if (try) {
1254 			struct iterinfo *iterinfop;
1255 
1256 			/*
1257 			 * at itree_create() time, we can expand simple
1258 			 * iterators.  anything else we'll punt on.
1259 			 */
1260 			iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
1261 			if (iterinfop != NULL) {
1262 				/* explicit iterator; not part of pathname */
1263 				valuep->t = UINT64;
1264 				valuep->v = (unsigned long long)iterinfop->num;
1265 				return (1);
1266 			}
1267 			return (0);
1268 		}
1269 
1270 		/* return address of struct node */
1271 		valuep->t = NODEPTR;
1272 		valuep->v = (uintptr_t)np;
1273 		return (1);
1274 
1275 	case T_QUOTE:
1276 		valuep->t = STRING;
1277 		valuep->v = (uintptr_t)np->u.quote.s;
1278 		return (1);
1279 
1280 	case T_FUNC:
1281 		return (eval_func(np, ex, epnames, np->u.func.arglist,
1282 				globals, croot, arrowp, try, valuep));
1283 
1284 	case T_NUM:
1285 		valuep->t = UINT64;
1286 		valuep->v = np->u.ull;
1287 		return (1);
1288 
1289 	default:
1290 		outfl(O_DIE, np->file, np->line,
1291 		    "eval_expr: unexpected node type: %s",
1292 		    ptree_nodetype2str(np->t));
1293 	}
1294 	/*NOTREACHED*/
1295 	return (0);
1296 }
1297 
1298 /*
1299  * eval_fru() and eval_asru() don't do much, but are called from a number
1300  * of places.
1301  */
1302 struct node *
1303 eval_fru(struct node *np)
1304 {
1305 	ASSERT(np->t == T_NAME);
1306 	return (np);
1307 }
1308 
1309 struct node *
1310 eval_asru(struct node *np)
1311 {
1312 	ASSERT(np->t == T_NAME);
1313 	return (np);
1314 }
1315