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