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