xref: /titanic_50/usr/src/cmd/fm/modules/common/eversholt/eval.c (revision 0fc2d9264767f09b82ca39f5ca9eaa84137a5f27)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
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 = (unsigned long long)eval_fru(np);
160 		return (1);
161 	} else if (funcname == L_asru) {
162 		valuep->t = NODEPTR;
163 		valuep->v = (unsigned long long)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 *)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,
246 				    " (\"%s\")", (char *)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 *)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 *)(preval.v))->t == T_NAME) {
333 					tree_free((struct node *)preval.v);
334 				}
335 
336 				if (vals[i].v == cmpval.v) {
337 					valuep->v = 1;
338 					break;
339 				}
340 			}
341 
342 			if (valuep->v)
343 				out(O_ALTFP|O_VERB2, "match.");
344 			else
345 				out(O_ALTFP|O_VERB2, "no match.");
346 
347 			for (i = 0; i < nvals; i++) {
348 				if (vals[i].t == NODEPTR) {
349 					tree_free((struct node *)vals[i].v);
350 					break;
351 				}
352 			}
353 			FREE(vals);
354 		}
355 		return (1);
356 	} else if (funcname == L_confcall) {
357 		return (!platform_confcall(np, globals, croot, arrowp, valuep));
358 	} else if (funcname == L_count) {
359 		struct stats *statp;
360 
361 		ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t));
362 
363 		valuep->t = UINT64;
364 		if ((statp = (struct stats *)
365 		    lut_lookup(Istats, np, (lut_cmp)istat_cmp)) == NULL)
366 			valuep->v = 0;
367 		else
368 			valuep->v = stats_counter_value(statp);
369 
370 		return (1);
371 	} else
372 		outfl(O_DIE, np->file, np->line,
373 		    "eval_func: unexpected func: %s", funcname);
374 	/*NOTREACHED*/
375 }
376 
377 static struct node *
378 eval_wildcardedname(struct node *np, struct lut *ex, struct node *epnames[])
379 {
380 	struct node *npstart, *npend, *npref, *newnp;
381 	struct node *np1, *np2, *retp;
382 	int i;
383 
384 	if (epnames == NULL || epnames[0] == NULL)
385 		return (NULL);
386 
387 	for (i = 0; epnames[i] != NULL; i++) {
388 		if (tree_namecmp(np, epnames[i]) == 0)
389 			return (NULL);
390 	}
391 
392 	/*
393 	 * get to this point if np does not match any of the entries in
394 	 * epnames.  check if np is a path that must preceded by a wildcard
395 	 * portion.  for this case we must first determine which epnames[]
396 	 * entry should be used for wildcarding.
397 	 */
398 	npstart = NULL;
399 	for (i = 0; epnames[i] != NULL; i++) {
400 		for (npref = epnames[i]; npref; npref = npref->u.name.next) {
401 			if (npref->u.name.s == np->u.name.s) {
402 				for (np1 = npref, np2 = np;
403 				    np1 != NULL && np2 != NULL;
404 				    np1 = np1->u.name.next,
405 					    np2 = np2->u.name.next) {
406 					if (np1->u.name.s != np2->u.name.s)
407 						break;
408 				}
409 				if (np2 == NULL) {
410 					npstart = epnames[i];
411 					npend = npref;
412 					if (np1 == NULL)
413 						break;
414 				}
415 			}
416 		}
417 
418 		if (npstart != NULL)
419 			break;
420 	}
421 
422 	if (npstart == NULL) {
423 		/* no match; np is not a path to be wildcarded */
424 		return (NULL);
425 	}
426 
427 	/*
428 	 * dup (npstart -- npend) which is the wildcarded portion.  all
429 	 * children should be T_NUMs.
430 	 */
431 	retp = NULL;
432 	for (npref = npstart;
433 	    ! (npref == NULL || npref == npend);
434 	    npref = npref->u.name.next) {
435 		newnp = newnode(T_NAME, np->file, np->line);
436 
437 		newnp->u.name.t = npref->u.name.t;
438 		newnp->u.name.s = npref->u.name.s;
439 		newnp->u.name.last = newnp;
440 		newnp->u.name.it = npref->u.name.it;
441 		newnp->u.name.cp = npref->u.name.cp;
442 
443 		ASSERT(npref->u.name.child != NULL);
444 		ASSERT(npref->u.name.child->t == T_NUM);
445 		newnp->u.name.child = newnode(T_NUM, np->file, np->line);
446 		newnp->u.name.child->u.ull = npref->u.name.child->u.ull;
447 
448 		if (retp == NULL) {
449 			retp = newnp;
450 		} else {
451 			retp->u.name.last->u.name.next = newnp;
452 			retp->u.name.last = newnp;
453 		}
454 	}
455 
456 	ASSERT(retp != NULL);
457 
458 	/* now append the nonwildcarded portion */
459 	retp = tree_name_append(retp, eval_dup(np, ex, NULL));
460 
461 	return (retp);
462 }
463 
464 static struct node *
465 eval_dup(struct node *np, struct lut *ex, struct node *epnames[])
466 {
467 	struct node *newnp;
468 
469 	if (np == NULL)
470 		return (NULL);
471 
472 	switch (np->t) {
473 	case T_GLOBID:
474 		return (tree_globid(np->u.globid.s, np->file, np->line));
475 
476 	case T_ASSIGN:
477 	case T_CONDIF:
478 	case T_CONDELSE:
479 	case T_NE:
480 	case T_EQ:
481 	case T_LT:
482 	case T_LE:
483 	case T_GT:
484 	case T_GE:
485 	case T_BITAND:
486 	case T_BITOR:
487 	case T_BITXOR:
488 	case T_BITNOT:
489 	case T_LSHIFT:
490 	case T_RSHIFT:
491 	case T_LIST:
492 	case T_AND:
493 	case T_OR:
494 	case T_NOT:
495 	case T_ADD:
496 	case T_SUB:
497 	case T_MUL:
498 	case T_DIV:
499 	case T_MOD:
500 		return (tree_expr(np->t,
501 				    eval_dup(np->u.expr.left, ex, epnames),
502 				    eval_dup(np->u.expr.right, ex, epnames)));
503 
504 	case T_NAME: {
505 		struct iterinfo *iterinfop;
506 		struct node *newchild = NULL;
507 
508 		iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
509 		if (iterinfop != NULL) {
510 			/* explicit iterator; not part of pathname */
511 			newnp = newnode(T_NUM, np->file, np->line);
512 			newnp->u.ull = iterinfop->num;
513 			return (newnp);
514 		}
515 
516 		/* see if np is a path with wildcard portion */
517 		newnp = eval_wildcardedname(np, ex, epnames);
518 		if (newnp != NULL)
519 			return (newnp);
520 
521 		/* turn off wildcarding for child */
522 		newchild = eval_dup(np->u.name.child, ex, NULL);
523 
524 		if (newchild != NULL) {
525 			if (newchild->t != T_NUM) {
526 				/*
527 				 * not a number, eh?  we must resolve this
528 				 * to a number.
529 				 */
530 				struct evalue value;
531 
532 				if (eval_expr(newchild, ex, epnames,
533 				    NULL, NULL, NULL, 1, &value) == 0 ||
534 				    value.t != UINT64) {
535 					outfl(O_DIE, np->file, np->line,
536 					    "eval_dup: could not resolve "
537 					    "iterator of %s", np->u.name.s);
538 				}
539 
540 				tree_free(newchild);
541 				newchild = newnode(T_NUM, np->file, np->line);
542 				newchild->u.ull = value.v;
543 			}
544 
545 			newnp = newnode(np->t, np->file, np->line);
546 			newnp->u.name.s = np->u.name.s;
547 			newnp->u.name.it = np->u.name.it;
548 			newnp->u.name.cp = np->u.name.cp;
549 
550 			newnp->u.name.last = newnp;
551 			newnp->u.name.child = newchild;
552 
553 			if (np->u.name.next != NULL) {
554 				/* turn off wildcarding for next */
555 				return (tree_name_append(newnp,
556 					eval_dup(np->u.name.next, ex, NULL)));
557 			} else {
558 				return (newnp);
559 			}
560 		} else {
561 			outfl(O_DIE, np->file, np->line,
562 			    "eval_dup: internal error: \"%s\" is neither "
563 			    "an iterator nor a pathname", np->u.name.s);
564 		}
565 		/*NOTREACHED*/
566 		break;
567 	}
568 
569 	case T_EVENT:
570 		newnp = newnode(T_NAME, np->file, np->line);
571 
572 		newnp->u.name.t = np->u.event.ename->u.name.t;
573 		newnp->u.name.s = np->u.event.ename->u.name.s;
574 		newnp->u.name.it = np->u.event.ename->u.name.it;
575 		newnp->u.name.last = newnp;
576 
577 		return (tree_event(newnp,
578 		    eval_dup(np->u.event.epname, ex, epnames),
579 		    eval_dup(np->u.event.eexprlist, ex, epnames)));
580 
581 	case T_FUNC:
582 		return (tree_func(np->u.func.s,
583 		    eval_dup(np->u.func.arglist, ex, epnames),
584 		    np->file, np->line));
585 
586 	case T_QUOTE:
587 		newnp = newnode(T_QUOTE, np->file, np->line);
588 		newnp->u.quote.s = np->u.quote.s;
589 		return (newnp);
590 
591 	case T_NUM:
592 		newnp = newnode(T_NUM, np->file, np->line);
593 		newnp->u.ull = np->u.ull;
594 		return (newnp);
595 
596 	default:
597 		outfl(O_DIE, np->file, np->line,
598 		    "eval_dup: unexpected node type: %s",
599 		    ptree_nodetype2str(np->t));
600 	}
601 	/*NOTREACHED*/
602 }
603 
604 /*
605  * eval_potential -- see if constraint is potentially true
606  *
607  * this function is used at instance tree creation time to see if
608  * any constraints are already known to be false.  if this function
609  * returns false, then the constraint will always be false and there's
610  * no need to include the propagation arrow in the instance tree.
611  *
612  * if this routine returns true, either the constraint is known to
613  * be always true (so there's no point in attaching the constraint
614  * to the propagation arrow in the instance tree), or the constraint
615  * contains "deferred" expressions like global variables or poller calls
616  * and so it must be evaluated during calls to fme_eval().  in this last
617  * case, where a constraint needs to be attached to the propagation arrow
618  * in the instance tree, this routine returns a newly created constraint
619  * in *newc where all the non-deferred things have been filled in.
620  *
621  * so in summary:
622  *
623  *	return of false: constraint can never be true, *newc will be NULL.
624  *
625  *	return of true with *newc unchanged: constraint will always be true.
626  *
627  *	return of true with *newc changed: use new constraint in *newc.
628  *
629  * the lookup table for all explicit iterators, ex, is passed in.
630  *
631  * *newc can either be NULL on entry, or if can contain constraints from
632  * previous calls to eval_potential() (i.e. for building up an instance
633  * tree constraint from several potential constraints).  if *newc already
634  * contains constraints, anything added to it will be joined by adding
635  * a T_AND node at the top of *newc.
636  */
637 int
638 eval_potential(struct node *np, struct lut *ex, struct node *epnames[],
639 	    struct node **newc)
640 {
641 	struct node *newnp;
642 	struct evalue value;
643 
644 	if (eval_expr(np, ex, epnames, NULL, NULL, NULL, 1, &value) == 0) {
645 		/*
646 		 * couldn't eval expression because
647 		 * it contains deferred items.  make
648 		 * a duplicate expression with all the
649 		 * non-deferred items expanded.
650 		 */
651 		newnp = eval_dup(np, ex, epnames);
652 
653 		if (*newc == NULL) {
654 			/*
655 			 * constraint is potentially true if deferred
656 			 * expression in newnp is true.  *newc was NULL
657 			 * so new constraint is just the one in newnp.
658 			 */
659 			*newc = newnp;
660 			return (1);
661 		} else {
662 			/*
663 			 * constraint is potentially true if deferred
664 			 * expression in newnp is true.  *newc already
665 			 * contained a constraint so add an AND with the
666 			 * constraint in newnp.
667 			 */
668 			*newc = tree_expr(T_AND, *newc, newnp);
669 			return (1);
670 		}
671 	} else if (value.t == UNDEFINED) {
672 		/* constraint can never be true */
673 		return (0);
674 	} else if (value.t == UINT64 && value.v == 0) {
675 		/* constraint can never be true */
676 		return (0);
677 	} else {
678 		/* constraint is always true (nothing deferred to eval) */
679 		return (1);
680 	}
681 }
682 
683 static int
684 check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype,
685 		struct node *np)
686 {
687 	/* auto-convert T_NAMES to strings */
688 	if (lp->t == NODEPTR && ((struct node *)(lp->v))->t == T_NAME) {
689 		char *s = ipath2str(NULL, ipath((struct node *)lp->v));
690 		lp->t = STRING;
691 		lp->v = (unsigned long long)stable(s);
692 		FREE(s);
693 		out(O_ALTFP|O_VERB2, "convert lhs path to \"%s\"",
694 		    (char *)lp->v);
695 	}
696 	if (rp != NULL &&
697 	    rp->t == NODEPTR && ((struct node *)(rp->v))->t == T_NAME) {
698 		char *s = ipath2str(NULL, ipath((struct node *)rp->v));
699 		rp->t = STRING;
700 		rp->v = (unsigned long long)stable(s);
701 		FREE(s);
702 		out(O_ALTFP|O_VERB2, "convert rhs path to \"%s\"",
703 		    (char *)rp->v);
704 	}
705 
706 	/* auto-convert strings to numbers */
707 	if (dtype == UINT64) {
708 		if (lp->t == STRING) {
709 			lp->t = UINT64;
710 			lp->v = strtoull((char *)lp->v, NULL, 0);
711 		}
712 		if (rp != NULL && rp->t == STRING) {
713 			rp->t = UINT64;
714 			rp->v = strtoull((char *)rp->v, NULL, 0);
715 		}
716 	}
717 
718 	if (dtype != UNDEFINED && lp->t != dtype) {
719 		outfl(O_OK, np->file, np->line,
720 			"invalid datatype of argument for operation %s",
721 			ptree_nodetype2str(np->t));
722 		return (1);
723 	}
724 
725 	if (rp != NULL && lp->t != rp->t) {
726 		outfl(O_OK, np->file, np->line,
727 			"mismatch in datatype of arguments for operation %s",
728 			ptree_nodetype2str(np->t));
729 		return (1);
730 	}
731 
732 	return (0);
733 }
734 
735 /*
736  * eval_expr -- evaluate expression into *valuep
737  *
738  * the meaning of the return value depends on the input value of try.
739  *
740  * for try == 1: if any deferred items are encounted, bail out and return
741  * false.  returns true if we made it through entire expression without
742  * hitting any deferred items.
743  *
744  * for try == 0: return true if all operations were performed successfully.
745  * return false if otherwise.  for example, any of the following conditions
746  * will result in a false return value:
747  *   - attempted use of an uninitialized global variable
748  *   - failure in function evaluation
749  *   - illegal arithmetic operation (argument out of range)
750  */
751 int
752 eval_expr(struct node *np, struct lut *ex, struct node *epnames[],
753 	struct lut **globals, struct config *croot, struct arrow *arrowp,
754 	int try, struct evalue *valuep)
755 {
756 	struct evalue *gval;
757 	struct evalue lval;
758 	struct evalue rval;
759 
760 	if (np == NULL) {
761 		valuep->t = UINT64;
762 		valuep->v = 1;	/* no constraint means "true" */
763 		return (1);
764 	}
765 
766 	valuep->t = UNDEFINED;
767 
768 	switch (np->t) {
769 	case T_GLOBID:
770 		if (try)
771 			return (0);
772 
773 		/*
774 		 * only handle case of getting (and not setting) the value
775 		 * of a global variable
776 		 */
777 		gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL);
778 		if (gval == NULL) {
779 			valuep->t = UNDEFINED;
780 			return (0);
781 		} else {
782 			valuep->t = gval->t;
783 			valuep->v = gval->v;
784 			return (1);
785 		}
786 
787 	case T_ASSIGN:
788 		if (try)
789 			return (0);
790 
791 		/*
792 		 * first evaluate rhs, then try to store value in lhs which
793 		 * should be a global variable
794 		 */
795 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
796 			    arrowp, try, &rval))
797 			return (0);
798 
799 		ASSERT(np->u.expr.left->t == T_GLOBID);
800 		gval = lut_lookup(*globals,
801 				(void *)np->u.expr.left->u.globid.s, NULL);
802 
803 		if (gval == NULL) {
804 			gval = MALLOC(sizeof (*gval));
805 			*globals = lut_add(*globals,
806 					(void *) np->u.expr.left->u.globid.s,
807 					gval, NULL);
808 		}
809 
810 		gval->t = rval.t;
811 		gval->v = rval.v;
812 
813 		if (gval->t == UINT64) {
814 			out(O_ALTFP|O_VERB2,
815 			    "assign $%s=%llu",
816 			    np->u.expr.left->u.globid.s, gval->v);
817 		} else {
818 			out(O_ALTFP|O_VERB2,
819 			    "assign $%s=\"%s\"",
820 			    np->u.expr.left->u.globid.s, (char *)gval->v);
821 		}
822 
823 		/*
824 		 * but always return true -- an assignment should not
825 		 * cause a constraint to be false.
826 		 */
827 		valuep->t = UINT64;
828 		valuep->v = 1;
829 		return (1);
830 
831 	case T_EQ:
832 #define	IMPLICIT_ASSIGN_IN_EQ
833 #ifdef IMPLICIT_ASSIGN_IN_EQ
834 		/*
835 		 * if lhs is an uninitialized global variable, perform
836 		 * an assignment.
837 		 *
838 		 * one insidious side effect of implicit assignment is
839 		 * that the "==" operator does not return a Boolean if
840 		 * implicit assignment was performed.
841 		 */
842 		if (try == 0 &&
843 		    np->u.expr.left->t == T_GLOBID &&
844 		    (gval = lut_lookup(*globals,
845 			(void *)np->u.expr.left->u.globid.s, NULL)) == NULL) {
846 			if (!eval_expr(np->u.expr.right, ex, epnames, globals,
847 					croot, arrowp, try, &rval))
848 				return (0);
849 
850 			gval = MALLOC(sizeof (*gval));
851 			*globals = lut_add(*globals,
852 					(void *) np->u.expr.left->u.globid.s,
853 					gval, NULL);
854 
855 			gval->t = rval.t;
856 			gval->v = rval.v;
857 			valuep->t = rval.t;
858 			valuep->v = rval.v;
859 			return (1);
860 		}
861 #endif  /* IMPLICIT_ASSIGN_IN_EQ */
862 
863 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
864 				arrowp, try, &lval))
865 			return (0);
866 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
867 				arrowp, try, &rval))
868 			return (0);
869 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
870 			return (0);
871 
872 		valuep->t = UINT64;
873 		valuep->v = (lval.v == rval.v);
874 		return (1);
875 
876 	case T_LT:
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, UINT64, np))
884 			return (0);
885 
886 		valuep->t = UINT64;
887 		valuep->v = (lval.v < rval.v);
888 		return (1);
889 
890 	case T_LE:
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_GT:
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_GE:
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_BITAND:
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 = lval.t;
943 		valuep->v = (lval.v & rval.v);
944 		return (1);
945 
946 	case T_BITOR:
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_BITXOR:
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_BITNOT:
975 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
976 				arrowp, try, &lval))
977 			return (0);
978 		ASSERT(np->u.expr.right == NULL);
979 		if (check_expr_args(&lval, NULL, UINT64, np))
980 			return (0);
981 
982 		valuep->t = UINT64;
983 		valuep->v = ~ lval.v;
984 		return (1);
985 
986 	case T_LSHIFT:
987 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
988 				arrowp, try, &lval))
989 			return (0);
990 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
991 				arrowp, try, &rval))
992 			return (0);
993 		if (check_expr_args(&lval, &rval, UINT64, np))
994 			return (0);
995 
996 		valuep->t = UINT64;
997 		valuep->v = (lval.v << rval.v);
998 		return (1);
999 
1000 	case T_RSHIFT:
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_CONDIF: {
1015 		struct node *retnp;
1016 		int dotrue = 0;
1017 
1018 		/*
1019 		 * evaluate
1020 		 *	expression ? stmtA [ : stmtB ]
1021 		 *
1022 		 * first see if expression is true or false, then determine
1023 		 * if stmtA (or stmtB, if it exists) should be evaluated.
1024 		 *
1025 		 * "dotrue = 1" means stmtA should be evaluated.
1026 		 */
1027 		if (eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1028 				arrowp, try, &lval) &&
1029 		    lval.t != UNDEFINED && lval.v != 0)
1030 			dotrue = 1;
1031 
1032 		ASSERT(np->u.expr.right != NULL);
1033 		if (np->u.expr.right->t == T_CONDELSE) {
1034 			if (dotrue)
1035 				retnp = np->u.expr.right->u.expr.left;
1036 			else
1037 				retnp = np->u.expr.right->u.expr.right;
1038 		} else {
1039 			/* no ELSE clause */
1040 			if (dotrue)
1041 				retnp = np->u.expr.right;
1042 			else {
1043 				valuep->t = UINT64;
1044 				valuep->v = 0;
1045 				return (0);
1046 			}
1047 		}
1048 
1049 		if (!eval_expr(retnp, ex, epnames, globals, croot,
1050 			    arrowp, try, valuep))
1051 			return (0);
1052 		return (1);
1053 	}
1054 
1055 	case T_CONDELSE:
1056 		/*
1057 		 * shouldn't get here, since T_CONDELSE is supposed to be
1058 		 * evaluated as part of T_CONDIF
1059 		 */
1060 		out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s",
1061 		    ptree_nodetype2str(np->t));
1062 		return (0);
1063 
1064 	case T_NE:
1065 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1066 				arrowp, try, &lval))
1067 			return (0);
1068 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1069 				arrowp, try, &rval))
1070 			return (0);
1071 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
1072 			return (0);
1073 
1074 		valuep->t = UINT64;
1075 		valuep->v = (lval.v != rval.v);
1076 		return (1);
1077 
1078 	case T_LIST:
1079 	case T_AND:
1080 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1081 				arrowp, try, valuep))
1082 			return (0);
1083 		if (valuep->v == 0) {
1084 			valuep->t = UINT64;
1085 			return (1);
1086 		}
1087 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1088 				arrowp, try, valuep))
1089 			return (0);
1090 		valuep->t = UINT64;
1091 		valuep->v = valuep->v == 0 ? 0 : 1;
1092 		return (1);
1093 
1094 	case T_OR:
1095 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1096 				arrowp, try, valuep))
1097 			return (0);
1098 		if (valuep->v != 0) {
1099 			valuep->t = UINT64;
1100 			valuep->v = 1;
1101 			return (1);
1102 		}
1103 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1104 				arrowp, try, valuep))
1105 			return (0);
1106 		valuep->t = UINT64;
1107 		valuep->v = valuep->v == 0 ? 0 : 1;
1108 		return (1);
1109 
1110 	case T_NOT:
1111 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1112 				arrowp, try, valuep))
1113 			return (0);
1114 		valuep->t = UINT64;
1115 		valuep->v = ! valuep->v;
1116 		return (1);
1117 
1118 	case T_ADD:
1119 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1120 				arrowp, try, &lval))
1121 			return (0);
1122 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1123 				arrowp, try, &rval))
1124 			return (0);
1125 		if (check_expr_args(&lval, &rval, UINT64, np))
1126 			return (0);
1127 
1128 		valuep->t = lval.t;
1129 		valuep->v = lval.v + rval.v;
1130 		return (1);
1131 
1132 	case T_SUB:
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 		/* since valuep is unsigned, return false if lval.v < rval.v */
1143 		if (lval.v < rval.v) {
1144 			out(O_ERR, "eval_expr: T_SUB result is out of range");
1145 			valuep->t = UNDEFINED;
1146 			return (0);
1147 		}
1148 
1149 		valuep->t = lval.t;
1150 		valuep->v = lval.v - rval.v;
1151 		return (1);
1152 
1153 	case T_MUL:
1154 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1155 				arrowp, try, &lval))
1156 			return (0);
1157 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1158 				arrowp, try, &rval))
1159 			return (0);
1160 		if (check_expr_args(&lval, &rval, UINT64, np))
1161 			return (0);
1162 
1163 		valuep->t = lval.t;
1164 		valuep->v = lval.v * rval.v;
1165 		return (1);
1166 
1167 	case T_DIV:
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 		/* return false if dividing by zero */
1178 		if (rval.v == 0) {
1179 			out(O_ERR, "eval_expr: T_DIV division by zero");
1180 			valuep->t = UNDEFINED;
1181 			return (0);
1182 		}
1183 
1184 		valuep->t = lval.t;
1185 		valuep->v = lval.v / rval.v;
1186 		return (1);
1187 
1188 	case T_MOD:
1189 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1190 				arrowp, try, &lval))
1191 			return (0);
1192 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
1193 				arrowp, try, &rval))
1194 			return (0);
1195 		if (check_expr_args(&lval, &rval, UINT64, np))
1196 			return (0);
1197 
1198 		/* return false if dividing by zero */
1199 		if (rval.v == 0) {
1200 			out(O_ERR, "eval_expr: T_MOD division by zero");
1201 			valuep->t = UNDEFINED;
1202 			return (0);
1203 		}
1204 
1205 		valuep->t = lval.t;
1206 		valuep->v = lval.v % rval.v;
1207 		return (1);
1208 
1209 	case T_NAME:
1210 		if (try) {
1211 			struct iterinfo *iterinfop;
1212 
1213 			/*
1214 			 * at itree_create() time, we can expand simple
1215 			 * iterators.  anything else we'll punt on.
1216 			 */
1217 			iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
1218 			if (iterinfop != NULL) {
1219 				/* explicit iterator; not part of pathname */
1220 				valuep->t = UINT64;
1221 				valuep->v = (unsigned long long)iterinfop->num;
1222 				return (1);
1223 			}
1224 			return (0);
1225 		}
1226 
1227 		/* return address of struct node */
1228 		valuep->t = NODEPTR;
1229 		valuep->v = (unsigned long long)np;
1230 		return (1);
1231 
1232 	case T_QUOTE:
1233 		valuep->t = STRING;
1234 		valuep->v = (unsigned long long)np->u.quote.s;
1235 		return (1);
1236 
1237 	case T_FUNC:
1238 		return (eval_func(np, ex, epnames, np->u.func.arglist,
1239 				globals, croot, arrowp, try, valuep));
1240 
1241 	case T_NUM:
1242 		valuep->t = UINT64;
1243 		valuep->v = np->u.ull;
1244 		return (1);
1245 
1246 	default:
1247 		outfl(O_DIE, np->file, np->line,
1248 		    "eval_expr: unexpected node type: %s",
1249 		    ptree_nodetype2str(np->t));
1250 	}
1251 	/*NOTREACHED*/
1252 }
1253 
1254 /*
1255  * eval_fru() and eval_asru() don't do much, but are called from a number
1256  * of places.
1257  */
1258 struct node *
1259 eval_fru(struct node *np)
1260 {
1261 	ASSERT(np->t == T_NAME);
1262 	return (np);
1263 }
1264 
1265 struct node *
1266 eval_asru(struct node *np)
1267 {
1268 	ASSERT(np->t == T_NAME);
1269 	return (np);
1270 }
1271