xref: /illumos-gate/usr/src/cmd/fm/modules/common/eversholt/eval.c (revision 3e8d8e182b274ca2da0da571da1f62acac10fe6f)
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 2005 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 "eval.h"
46 #include "config.h"
47 #include "platform.h"
48 
49 
50 static struct node *eval_dup(struct node *np, struct lut *ex,
51 			    struct node *epnames[]);
52 
53 /*
54  * begins_with -- return true if rhs path begins with everything in lhs path
55  */
56 static int
57 begins_with(struct node *lhs, struct node *rhs)
58 {
59 	int lnum;
60 	int rnum;
61 
62 	if (lhs == NULL)
63 		return (1);	/* yep -- it all matched */
64 
65 	if (rhs == NULL)
66 		return (0);	/* nope, ran out of rhs first */
67 
68 	ASSERTeq(lhs->t, T_NAME, ptree_nodetype2str);
69 	ASSERTeq(rhs->t, T_NAME, ptree_nodetype2str);
70 
71 	if (lhs->u.name.s != rhs->u.name.s)
72 		return (0);	/* nope, different component names */
73 
74 	if (lhs->u.name.child && lhs->u.name.child->t == T_NUM)
75 		lnum = (int)lhs->u.name.child->u.ull;
76 	else
77 		out(O_DIE, "begins_with: unexpected lhs child");
78 
79 	if (rhs->u.name.child && rhs->u.name.child->t == T_NUM)
80 		rnum = (int)rhs->u.name.child->u.ull;
81 	else
82 		out(O_DIE, "begins_with: unexpected rhs child");
83 
84 	if (lnum != rnum)
85 		return (0);	/* nope, instance numbers were different */
86 
87 	return (begins_with(lhs->u.name.next, rhs->u.name.next));
88 }
89 
90 /*
91  * evaluate a variety of functions and place result in valuep.  return 1 if
92  * function evaluation was successful; 0 if otherwise (e.g., the case of an
93  * invalid argument to the function)
94  */
95 /*ARGSUSED*/
96 static int
97 eval_func(struct node *funcnp, struct lut *ex, struct node *epnames[],
98     struct node *np, struct lut **globals,
99     struct config *croot, struct arrow *arrowp, int try, struct evalue *valuep)
100 {
101 	const char *funcname = funcnp->u.func.s;
102 
103 	if (funcname == L_within) {
104 		/* within()'s are not really constraints -- always true */
105 		valuep->t = UINT64;
106 		valuep->v = 1;
107 		return (1);
108 	} else if (funcname == L_is_under) {
109 		struct node *lhs;
110 		struct node *rhs;
111 
112 		if (np->u.expr.left->t == T_NAME)
113 			lhs = np->u.expr.left;
114 		else if (np->u.expr.left->u.func.s == L_fru)
115 			lhs = eval_fru(np->u.expr.left->u.func.arglist);
116 		else if (np->u.expr.left->u.func.s == L_asru)
117 			lhs = eval_asru(np->u.expr.left->u.func.arglist);
118 		else
119 			out(O_DIE, "is_under: unexpected lhs type: %s",
120 			    ptree_nodetype2str(np->u.expr.left->t));
121 
122 		if (np->u.expr.right->t == T_NAME)
123 			rhs = np->u.expr.right;
124 		else if (np->u.expr.right->u.func.s == L_fru)
125 			rhs = eval_fru(np->u.expr.right->u.func.arglist);
126 		else if (np->u.expr.right->u.func.s == L_asru)
127 			rhs = eval_asru(np->u.expr.right->u.func.arglist);
128 		else
129 			out(O_DIE, "is_under: unexpected rhs type: %s",
130 			    ptree_nodetype2str(np->u.expr.right->t));
131 
132 		/* eval_dup will expand wildcards, iterators, etc... */
133 		lhs = eval_dup(lhs, ex, epnames);
134 		rhs = eval_dup(rhs, ex, epnames);
135 		valuep->t = UINT64;
136 		valuep->v = begins_with(lhs, rhs);
137 
138 		out(O_ALTFP|O_VERB2|O_NONL, "eval_func:is_under(");
139 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, lhs);
140 		out(O_ALTFP|O_VERB2|O_NONL, ",");
141 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, rhs);
142 		out(O_ALTFP|O_VERB2, ") returned %d", (int)valuep->v);
143 
144 		tree_free(lhs);
145 		tree_free(rhs);
146 
147 		return (1);
148 	}
149 
150 	if (try)
151 		return (0);
152 
153 	if (funcname == L_fru) {
154 		valuep->t = NODEPTR;
155 		valuep->v = (unsigned long long)eval_fru(np);
156 		return (1);
157 	} else if (funcname == L_asru) {
158 		valuep->t = NODEPTR;
159 		valuep->v = (unsigned long long)eval_asru(np);
160 		return (1);
161 	} else if (funcname == L_call) {
162 		return (! platform_call(np, globals, croot, arrowp, valuep));
163 	} else if (funcname == L_is_connected) {
164 		return (! config_is_connected(np, croot, valuep));
165 	} else if (funcname == L_is_on) {
166 		return (! config_is_on(np, croot, valuep));
167 	} else if (funcname == L_is_present) {
168 		return (! config_is_present(np, croot, valuep));
169 	} else if (funcname == L_is_type) {
170 		return (! config_is_type(np, croot, valuep));
171 	} else if (funcname == L_confprop) {
172 		return (! config_confprop(np, croot, valuep));
173 	} else if (funcname == L_envprop) {
174 		outfl(O_DIE, np->file, np->line,
175 		    "eval_func: %s not yet supported", funcname);
176 	} else if (funcname == L_payloadprop) {
177 		outfl(O_ALTFP|O_VERB|O_NONL, np->file, np->line,
178 		    "payloadprop(\"%s\") ", np->u.quote.s);
179 		if (funcnp->u.func.cachedval != NULL) {
180 			*valuep = *(struct evalue *)(funcnp->u.func.cachedval);
181 
182 			switch (valuep->t) {
183 			case UINT64:
184 			case NODEPTR:
185 				out(O_ALTFP|O_VERB, "cached: %llu", valuep->v);
186 				break;
187 			case STRING:
188 				out(O_ALTFP|O_VERB, "cached: \"%s\"",
189 				    (char *)valuep->v);
190 				break;
191 			default:
192 				out(O_ALTFP|O_VERB, "undefined");
193 				break;
194 			}
195 
196 			return (1);
197 		} else if (platform_payloadprop(np, valuep)) {
198 			/* platform_payloadprop() returned false, pass it on */
199 			out(O_ALTFP|O_VERB, "failed.");
200 			return (0);
201 		} else {
202 			/* got back true, cache the value */
203 			funcnp->u.func.cachedval =
204 			    MALLOC(sizeof (struct evalue));
205 			*(struct evalue *)(funcnp->u.func.cachedval) =
206 			    *valuep;
207 
208 			switch (valuep->t) {
209 			case UINT64:
210 			case NODEPTR:
211 				out(O_ALTFP|O_VERB, "cached: %llu", valuep->v);
212 				break;
213 			case STRING:
214 				out(O_ALTFP|O_VERB, "cached: \"%s\"",
215 				    (char *)valuep->v);
216 				break;
217 			default:
218 				out(O_ALTFP|O_VERB, "undefined");
219 				break;
220 			}
221 
222 			return (1);
223 		}
224 	} else
225 		outfl(O_DIE, np->file, np->line,
226 		    "eval_func: unexpected func: %s", funcname);
227 	/*NOTREACHED*/
228 }
229 
230 static struct node *
231 eval_wildcardedname(struct node *np, struct lut *ex, struct node *epnames[])
232 {
233 	struct node *npstart, *npend, *npref, *newnp;
234 	struct node *np1, *np2, *retp;
235 	int i;
236 
237 	if (epnames == NULL || epnames[0] == NULL)
238 		return (NULL);
239 
240 	for (i = 0; epnames[i] != NULL; i++) {
241 		if (tree_namecmp(np, epnames[i]) == 0)
242 			return (NULL);
243 	}
244 
245 	/*
246 	 * get to this point if np does not match any of the entries in
247 	 * epnames.  check if np is a path that must preceded by a wildcard
248 	 * portion.  for this case we must first determine which epnames[]
249 	 * entry should be used for wildcarding.
250 	 */
251 	npstart = NULL;
252 	for (i = 0; epnames[i] != NULL; i++) {
253 		for (npref = epnames[i]; npref; npref = npref->u.name.next) {
254 			if (npref->u.name.s == np->u.name.s) {
255 				for (np1 = npref, np2 = np;
256 				    np1 != NULL && np2 != NULL;
257 				    np1 = np1->u.name.next,
258 					    np2 = np2->u.name.next) {
259 					if (np1->u.name.s != np2->u.name.s)
260 						break;
261 				}
262 				if (np2 == NULL) {
263 					npstart = epnames[i];
264 					npend = npref;
265 					if (np1 == NULL)
266 						break;
267 				}
268 			}
269 		}
270 
271 		if (npstart != NULL)
272 			break;
273 	}
274 
275 	if (npstart == NULL) {
276 		/* no match; np is not a path to be wildcarded */
277 		return (NULL);
278 	}
279 
280 	/*
281 	 * dup (npstart -- npend) which is the wildcarded portion.  all
282 	 * children should be T_NUMs.
283 	 */
284 	retp = NULL;
285 	for (npref = npstart;
286 	    ! (npref == NULL || npref == npend);
287 	    npref = npref->u.name.next) {
288 		newnp = newnode(T_NAME, np->file, np->line);
289 
290 		newnp->u.name.t = npref->u.name.t;
291 		newnp->u.name.s = npref->u.name.s;
292 		newnp->u.name.last = newnp;
293 		newnp->u.name.it = npref->u.name.it;
294 		newnp->u.name.cp = npref->u.name.cp;
295 
296 		ASSERT(npref->u.name.child != NULL);
297 		ASSERT(npref->u.name.child->t == T_NUM);
298 		newnp->u.name.child = newnode(T_NUM, np->file, np->line);
299 		newnp->u.name.child->u.ull = npref->u.name.child->u.ull;
300 
301 		if (retp == NULL) {
302 			retp = newnp;
303 		} else {
304 			retp->u.name.last->u.name.next = newnp;
305 			retp->u.name.last = newnp;
306 		}
307 	}
308 
309 	ASSERT(retp != NULL);
310 
311 	/* now append the nonwildcarded portion */
312 	retp = tree_name_append(retp, eval_dup(np, ex, NULL));
313 
314 	return (retp);
315 }
316 
317 static struct node *
318 eval_dup(struct node *np, struct lut *ex, struct node *epnames[])
319 {
320 	struct node *newnp;
321 
322 	if (np == NULL)
323 		return (NULL);
324 
325 	switch (np->t) {
326 	case T_GLOBID:
327 		return (tree_globid(np->u.globid.s, np->file, np->line));
328 
329 	case T_ASSIGN:
330 	case T_CONDIF:
331 	case T_CONDELSE:
332 	case T_NE:
333 	case T_EQ:
334 	case T_LT:
335 	case T_LE:
336 	case T_GT:
337 	case T_GE:
338 	case T_BITAND:
339 	case T_BITOR:
340 	case T_BITXOR:
341 	case T_BITNOT:
342 	case T_LSHIFT:
343 	case T_RSHIFT:
344 	case T_LIST:
345 	case T_AND:
346 	case T_OR:
347 	case T_NOT:
348 	case T_ADD:
349 	case T_SUB:
350 	case T_MUL:
351 	case T_DIV:
352 	case T_MOD:
353 		return (tree_expr(np->t,
354 				    eval_dup(np->u.expr.left, ex, epnames),
355 				    eval_dup(np->u.expr.right, ex, epnames)));
356 
357 	case T_NAME: {
358 		struct iterinfo *iterinfop;
359 		struct node *newchild = NULL;
360 
361 		iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
362 		if (iterinfop != NULL) {
363 			/* explicit iterator; not part of pathname */
364 			newnp = newnode(T_NUM, np->file, np->line);
365 			newnp->u.ull = iterinfop->num;
366 			return (newnp);
367 		}
368 
369 		/* see if np is a path with wildcard portion */
370 		newnp = eval_wildcardedname(np, ex, epnames);
371 		if (newnp != NULL)
372 			return (newnp);
373 
374 		/* turn off wildcarding for child */
375 		newchild = eval_dup(np->u.name.child, ex, NULL);
376 
377 		if (newchild != NULL) {
378 			if (newchild->t != T_NUM) {
379 				/*
380 				 * not a number, eh?  we must resolve this
381 				 * to a number.
382 				 */
383 				struct evalue value;
384 
385 				if (eval_expr(newchild, ex, epnames,
386 				    NULL, NULL, NULL, 1, &value) == 0 ||
387 				    value.t != UINT64) {
388 					outfl(O_DIE, np->file, np->line,
389 					    "eval_dup: could not resolve "
390 					    "iterator of %s", np->u.name.s);
391 				}
392 
393 				tree_free(newchild);
394 				newchild = newnode(T_NUM, np->file, np->line);
395 				newchild->u.ull = value.v;
396 			}
397 
398 			newnp = newnode(np->t, np->file, np->line);
399 			newnp->u.name.s = np->u.name.s;
400 			newnp->u.name.it = np->u.name.it;
401 			newnp->u.name.cp = np->u.name.cp;
402 
403 			newnp->u.name.last = newnp;
404 			newnp->u.name.child = newchild;
405 
406 			if (np->u.name.next != NULL) {
407 				/* turn off wildcarding for next */
408 				return (tree_name_append(newnp,
409 					eval_dup(np->u.name.next, ex, NULL)));
410 			} else {
411 				return (newnp);
412 			}
413 		} else {
414 			outfl(O_DIE, np->file, np->line,
415 			    "eval_dup: internal error: \"%s\" is neither "
416 			    "an iterator nor a pathname", np->u.name.s);
417 		}
418 		/*NOTREACHED*/
419 		break;
420 	}
421 
422 	case T_FUNC:
423 		return (tree_func(np->u.func.s,
424 		    eval_dup(np->u.func.arglist, ex, epnames),
425 		    np->file, np->line));
426 
427 	case T_QUOTE:
428 		newnp = newnode(T_QUOTE, np->file, np->line);
429 		newnp->u.quote.s = np->u.quote.s;
430 		return (newnp);
431 
432 	case T_NUM:
433 		newnp = newnode(T_NUM, np->file, np->line);
434 		newnp->u.ull = np->u.ull;
435 		return (newnp);
436 
437 	default:
438 		outfl(O_DIE, np->file, np->line,
439 		    "eval_dup: unexpected node type: %s",
440 		    ptree_nodetype2str(np->t));
441 	}
442 	/*NOTREACHED*/
443 }
444 
445 /*
446  * eval_potential -- see if constraint is potentially true
447  *
448  * this function is used at instance tree creation time to see if
449  * any constraints are already known to be false.  if this function
450  * returns false, then the constraint will always be false and there's
451  * no need to include the propagation arrow in the instance tree.
452  *
453  * if this routine returns true, either the constraint is known to
454  * be always true (so there's no point in attaching the constraint
455  * to the propagation arrow in the instance tree), or the constraint
456  * contains "deferred" expressions like global variables or poller calls
457  * and so it must be evaluated during calls to fme_eval().  in this last
458  * case, where a constraint needs to be attached to the propagation arrow
459  * in the instance tree, this routine returns a newly created constraint
460  * in *newc where all the non-deferred things have been filled in.
461  *
462  * so in summary:
463  *
464  *	return of false: constraint can never be true, *newc will be NULL.
465  *
466  *	return of true with *newc unchanged: constraint will always be true.
467  *
468  *	return of true with *newc changed: use new constraint in *newc.
469  *
470  * the lookup table for all explicit iterators, ex, is passed in.
471  *
472  * *newc can either be NULL on entry, or if can contain constraints from
473  * previous calls to eval_potential() (i.e. for building up an instance
474  * tree constraint from several potential constraints).  if *newc already
475  * contains constraints, anything added to it will be joined by adding
476  * a T_AND node at the top of *newc.
477  */
478 int
479 eval_potential(struct node *np, struct lut *ex, struct node *epnames[],
480 	    struct node **newc)
481 {
482 	struct node *newnp;
483 	struct evalue value;
484 
485 	if (eval_expr(np, ex, epnames, NULL, NULL, NULL, 1, &value) == 0) {
486 		/*
487 		 * couldn't eval expression because
488 		 * it contains deferred items.  make
489 		 * a duplicate expression with all the
490 		 * non-deferred items expanded.
491 		 */
492 		newnp = eval_dup(np, ex, epnames);
493 
494 		if (*newc == NULL) {
495 			/*
496 			 * constraint is potentially true if deferred
497 			 * expression in newnp is true.  *newc was NULL
498 			 * so new constraint is just the one in newnp.
499 			 */
500 			*newc = newnp;
501 			return (1);
502 		} else {
503 			/*
504 			 * constraint is potentially true if deferred
505 			 * expression in newnp is true.  *newc already
506 			 * contained a constraint so add an AND with the
507 			 * constraint in newnp.
508 			 */
509 			*newc = tree_expr(T_AND, *newc, newnp);
510 			return (1);
511 		}
512 	} else if (value.t == UNDEFINED) {
513 		/* constraint can never be true */
514 		return (0);
515 	} else if (value.t == UINT64 && value.v == 0) {
516 		/* constraint can never be true */
517 		return (0);
518 	} else {
519 		/* constraint is always true (nothing deferred to eval) */
520 		return (1);
521 	}
522 }
523 
524 static int
525 check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype,
526 		struct node *np)
527 {
528 	if (dtype != UNDEFINED && lp->t != dtype) {
529 		outfl(O_OK, np->file, np->line,
530 			"invalid datatype of argument for operation %s",
531 			ptree_nodetype2str(np->t));
532 		return (1);
533 	}
534 
535 	if (rp != NULL && lp->t != rp->t) {
536 		outfl(O_OK, np->file, np->line,
537 			"mismatch in datatype of arguments for operation %s",
538 			ptree_nodetype2str(np->t));
539 		return (1);
540 	}
541 
542 	return (0);
543 }
544 
545 /*
546  * eval_expr -- evaluate expression into *valuep
547  *
548  * the meaning of the return value depends on the input value of try.
549  *
550  * for try == 1: if any deferred items are encounted, bail out and return
551  * false.  returns true if we made it through entire expression without
552  * hitting any deferred items.
553  *
554  * for try == 0: return true if all operations were performed successfully.
555  * return false if otherwise.  for example, any of the following conditions
556  * will result in a false return value:
557  *   - attempted use of an uninitialized global variable
558  *   - failure in function evaluation
559  *   - illegal arithmetic operation (argument out of range)
560  */
561 int
562 eval_expr(struct node *np, struct lut *ex, struct node *epnames[],
563 	struct lut **globals, struct config *croot, struct arrow *arrowp,
564 	int try, struct evalue *valuep)
565 {
566 	struct evalue *gval;
567 	struct evalue lval;
568 	struct evalue rval;
569 
570 	if (np == NULL) {
571 		valuep->t = UINT64;
572 		valuep->v = 1;	/* no constraint means "true" */
573 		return (1);
574 	}
575 
576 	valuep->t = UNDEFINED;
577 
578 	switch (np->t) {
579 	case T_GLOBID:
580 		if (try)
581 			return (0);
582 
583 		/*
584 		 * only handle case of getting (and not setting) the value
585 		 * of a global variable
586 		 */
587 		gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL);
588 		if (gval == NULL) {
589 			valuep->t = UNDEFINED;
590 			return (0);
591 		} else {
592 			valuep->t = gval->t;
593 			valuep->v = gval->v;
594 			return (1);
595 		}
596 
597 	case T_ASSIGN:
598 		if (try)
599 			return (0);
600 
601 		/*
602 		 * first evaluate rhs, then try to store value in lhs which
603 		 * should be a global variable
604 		 */
605 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
606 			    arrowp, try, &rval))
607 			return (0);
608 
609 		ASSERT(np->u.expr.left->t == T_GLOBID);
610 		gval = lut_lookup(*globals,
611 				(void *)np->u.expr.left->u.globid.s, NULL);
612 
613 		if (gval == NULL) {
614 			gval = MALLOC(sizeof (*gval));
615 			*globals = lut_add(*globals,
616 					(void *) np->u.expr.left->u.globid.s,
617 					gval, NULL);
618 		}
619 
620 		gval->t = rval.t;
621 		gval->v = rval.v;
622 		valuep->t = rval.t;
623 		valuep->v = rval.v;
624 		return (1);
625 
626 	case T_EQ:
627 #define	IMPLICIT_ASSIGN_IN_EQ
628 #ifdef IMPLICIT_ASSIGN_IN_EQ
629 		/*
630 		 * if lhs is an uninitialized global variable, perform
631 		 * an assignment.
632 		 *
633 		 * one insidious side effect of implicit assignment is
634 		 * that the "==" operator does not return a Boolean if
635 		 * implicit assignment was performed.
636 		 */
637 		if (try == 0 &&
638 		    np->u.expr.left->t == T_GLOBID &&
639 		    (gval = lut_lookup(*globals,
640 			(void *)np->u.expr.left->u.globid.s, NULL)) == NULL) {
641 			if (!eval_expr(np->u.expr.right, ex, epnames, globals,
642 					croot, arrowp, try, &rval))
643 				return (0);
644 
645 			gval = MALLOC(sizeof (*gval));
646 			*globals = lut_add(*globals,
647 					(void *) np->u.expr.left->u.globid.s,
648 					gval, NULL);
649 
650 			gval->t = rval.t;
651 			gval->v = rval.v;
652 			valuep->t = rval.t;
653 			valuep->v = rval.v;
654 			return (1);
655 		}
656 #endif  /* IMPLICIT_ASSIGN_IN_EQ */
657 
658 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
659 				arrowp, try, &lval))
660 			return (0);
661 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
662 				arrowp, try, &rval))
663 			return (0);
664 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
665 			return (0);
666 
667 		valuep->t = UINT64;
668 		valuep->v = (lval.v == rval.v);
669 		return (1);
670 
671 	case T_LT:
672 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
673 				arrowp, try, &lval))
674 			return (0);
675 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
676 				arrowp, try, &rval))
677 			return (0);
678 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
679 			return (0);
680 
681 		valuep->t = UINT64;
682 		valuep->v = (lval.v < rval.v);
683 		return (1);
684 
685 	case T_LE:
686 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
687 				arrowp, try, &lval))
688 			return (0);
689 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
690 				arrowp, try, &rval))
691 			return (0);
692 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
693 			return (0);
694 
695 		valuep->t = UINT64;
696 		valuep->v = (lval.v <= rval.v);
697 		return (1);
698 
699 	case T_GT:
700 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
701 				arrowp, try, &lval))
702 			return (0);
703 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
704 				arrowp, try, &rval))
705 			return (0);
706 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
707 			return (0);
708 
709 		valuep->t = UINT64;
710 		valuep->v = (lval.v > rval.v);
711 		return (1);
712 
713 	case T_GE:
714 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
715 				arrowp, try, &lval))
716 			return (0);
717 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
718 				arrowp, try, &rval))
719 			return (0);
720 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
721 			return (0);
722 
723 		valuep->t = UINT64;
724 		valuep->v = (lval.v >= rval.v);
725 		return (1);
726 
727 	case T_BITAND:
728 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
729 				arrowp, try, &lval))
730 			return (0);
731 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
732 				arrowp, try, &rval))
733 			return (0);
734 		if (check_expr_args(&lval, &rval, UINT64, np))
735 			return (0);
736 
737 		valuep->t = lval.t;
738 		valuep->v = (lval.v & rval.v);
739 		return (1);
740 
741 	case T_BITOR:
742 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
743 				arrowp, try, &lval))
744 			return (0);
745 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
746 				arrowp, try, &rval))
747 			return (0);
748 		if (check_expr_args(&lval, &rval, UINT64, np))
749 			return (0);
750 
751 		valuep->t = lval.t;
752 		valuep->v = (lval.v | rval.v);
753 		return (1);
754 
755 	case T_BITXOR:
756 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
757 				arrowp, try, &lval))
758 			return (0);
759 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
760 				arrowp, try, &rval))
761 			return (0);
762 		if (check_expr_args(&lval, &rval, UINT64, np))
763 			return (0);
764 
765 		valuep->t = lval.t;
766 		valuep->v = (lval.v ^ rval.v);
767 		return (1);
768 
769 	case T_BITNOT:
770 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
771 				arrowp, try, &lval))
772 			return (0);
773 		ASSERT(np->u.expr.right == NULL);
774 		if (check_expr_args(&lval, NULL, UINT64, np))
775 			return (0);
776 
777 		valuep->t = UINT64;
778 		valuep->v = ~ lval.v;
779 		return (1);
780 
781 	case T_LSHIFT:
782 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
783 				arrowp, try, &lval))
784 			return (0);
785 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
786 				arrowp, try, &rval))
787 			return (0);
788 		if (check_expr_args(&lval, &rval, UINT64, np))
789 			return (0);
790 
791 		valuep->t = UINT64;
792 		valuep->v = (lval.v << rval.v);
793 		return (1);
794 
795 	case T_RSHIFT:
796 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
797 				arrowp, try, &lval))
798 			return (0);
799 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
800 				arrowp, try, &rval))
801 			return (0);
802 		if (check_expr_args(&lval, &rval, UINT64, np))
803 			return (0);
804 
805 		valuep->t = UINT64;
806 		valuep->v = (lval.v >> rval.v);
807 		return (1);
808 
809 	case T_CONDIF: {
810 		struct node *retnp;
811 		int dotrue = 0;
812 
813 		/*
814 		 * evaluate
815 		 *	expression ? stmtA [ : stmtB ]
816 		 *
817 		 * first see if expression is true or false, then determine
818 		 * if stmtA (or stmtB, if it exists) should be evaluated.
819 		 *
820 		 * "dotrue = 1" means stmtA should be evaluated.
821 		 */
822 		if (eval_expr(np->u.expr.left, ex, epnames, globals, croot,
823 				arrowp, try, &lval) &&
824 		    lval.t != UNDEFINED && lval.v != 0)
825 			dotrue = 1;
826 
827 		ASSERT(np->u.expr.right != NULL);
828 		if (np->u.expr.right->t == T_CONDELSE) {
829 			if (dotrue)
830 				retnp = np->u.expr.right->u.expr.left;
831 			else
832 				retnp = np->u.expr.right->u.expr.right;
833 		} else {
834 			/* no ELSE clause */
835 			if (dotrue)
836 				retnp = np->u.expr.right;
837 			else {
838 				valuep->t = UINT64;
839 				valuep->v = 0;
840 				return (0);
841 			}
842 		}
843 
844 		if (!eval_expr(retnp, ex, epnames, globals, croot,
845 			    arrowp, try, valuep))
846 			return (0);
847 		return (1);
848 	}
849 
850 	case T_CONDELSE:
851 		/*
852 		 * shouldn't get here, since T_CONDELSE is supposed to be
853 		 * evaluated as part of T_CONDIF
854 		 */
855 		out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s",
856 		    ptree_nodetype2str(np->t));
857 		return (0);
858 
859 	case T_NE:
860 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
861 				arrowp, try, &lval))
862 			return (0);
863 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
864 				arrowp, try, &rval))
865 			return (0);
866 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
867 			return (0);
868 
869 		valuep->t = UINT64;
870 		valuep->v = (lval.v != rval.v);
871 		return (1);
872 
873 	case T_LIST:
874 	case T_AND:
875 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
876 				arrowp, try, valuep))
877 			return (0);
878 		if (valuep->v == 0) {
879 			valuep->t = UINT64;
880 			return (1);
881 		}
882 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
883 				arrowp, try, valuep))
884 			return (0);
885 		valuep->t = UINT64;
886 		valuep->v = valuep->v == 0 ? 0 : 1;
887 		return (1);
888 
889 	case T_OR:
890 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
891 				arrowp, try, valuep))
892 			return (0);
893 		if (valuep->v != 0) {
894 			valuep->t = UINT64;
895 			valuep->v = 1;
896 			return (1);
897 		}
898 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
899 				arrowp, try, valuep))
900 			return (0);
901 		valuep->t = UINT64;
902 		valuep->v = valuep->v == 0 ? 0 : 1;
903 		return (1);
904 
905 	case T_NOT:
906 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
907 				arrowp, try, valuep))
908 			return (0);
909 		valuep->t = UINT64;
910 		valuep->v = ! valuep->v;
911 		return (1);
912 
913 	case T_ADD:
914 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
915 				arrowp, try, &lval))
916 			return (0);
917 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
918 				arrowp, try, &rval))
919 			return (0);
920 		if (check_expr_args(&lval, &rval, UINT64, np))
921 			return (0);
922 
923 		valuep->t = lval.t;
924 		valuep->v = lval.v + rval.v;
925 		return (1);
926 
927 	case T_SUB:
928 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
929 				arrowp, try, &lval))
930 			return (0);
931 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
932 				arrowp, try, &rval))
933 			return (0);
934 		if (check_expr_args(&lval, &rval, UINT64, np))
935 			return (0);
936 
937 		/* since valuep is unsigned, return false if lval.v < rval.v */
938 		if (lval.v < rval.v) {
939 			out(O_ERR, "eval_expr: T_SUB result is out of range");
940 			valuep->t = UNDEFINED;
941 			return (0);
942 		}
943 
944 		valuep->t = lval.t;
945 		valuep->v = lval.v - rval.v;
946 		return (1);
947 
948 	case T_MUL:
949 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
950 				arrowp, try, &lval))
951 			return (0);
952 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
953 				arrowp, try, &rval))
954 			return (0);
955 		if (check_expr_args(&lval, &rval, UINT64, np))
956 			return (0);
957 
958 		valuep->t = lval.t;
959 		valuep->v = lval.v * rval.v;
960 		return (1);
961 
962 	case T_DIV:
963 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
964 				arrowp, try, &lval))
965 			return (0);
966 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
967 				arrowp, try, &rval))
968 			return (0);
969 		if (check_expr_args(&lval, &rval, UINT64, np))
970 			return (0);
971 
972 		/* return false if dividing by zero */
973 		if (rval.v == 0) {
974 			out(O_ERR, "eval_expr: T_DIV division by zero");
975 			valuep->t = UNDEFINED;
976 			return (0);
977 		}
978 
979 		valuep->t = lval.t;
980 		valuep->v = lval.v / rval.v;
981 		return (1);
982 
983 	case T_MOD:
984 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
985 				arrowp, try, &lval))
986 			return (0);
987 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
988 				arrowp, try, &rval))
989 			return (0);
990 		if (check_expr_args(&lval, &rval, UINT64, np))
991 			return (0);
992 
993 		/* return false if dividing by zero */
994 		if (rval.v == 0) {
995 			out(O_ERR, "eval_expr: T_MOD division by zero");
996 			valuep->t = UNDEFINED;
997 			return (0);
998 		}
999 
1000 		valuep->t = lval.t;
1001 		valuep->v = lval.v % rval.v;
1002 		return (1);
1003 
1004 	case T_NAME:
1005 		if (try) {
1006 			struct iterinfo *iterinfop;
1007 
1008 			/*
1009 			 * at itree_create() time, we can expand simple
1010 			 * iterators.  anything else we'll punt on.
1011 			 */
1012 			iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
1013 			if (iterinfop != NULL) {
1014 				/* explicit iterator; not part of pathname */
1015 				valuep->t = UINT64;
1016 				valuep->v = (unsigned long long)iterinfop->num;
1017 				return (1);
1018 			}
1019 			return (0);
1020 		}
1021 
1022 		/* return address of struct node */
1023 		valuep->t = NODEPTR;
1024 		valuep->v = (unsigned long long)np;
1025 		return (1);
1026 
1027 	case T_QUOTE:
1028 		valuep->t = STRING;
1029 		valuep->v = (unsigned long long)np->u.quote.s;
1030 		return (1);
1031 
1032 	case T_FUNC:
1033 		return (eval_func(np, ex, epnames, np->u.func.arglist,
1034 				globals, croot, arrowp, try, valuep));
1035 
1036 	case T_NUM:
1037 		valuep->t = UINT64;
1038 		valuep->v = np->u.ull;
1039 		return (1);
1040 
1041 	default:
1042 		outfl(O_DIE, np->file, np->line,
1043 		    "eval_expr: unexpected node type: %s",
1044 		    ptree_nodetype2str(np->t));
1045 	}
1046 	/*NOTREACHED*/
1047 }
1048 
1049 /*
1050  * eval_fru() and eval_asru() don't do much, but are called from a number
1051  * of places.
1052  */
1053 struct node *
1054 eval_fru(struct node *np)
1055 {
1056 	ASSERT(np->t == T_NAME);
1057 	return (np);
1058 }
1059 
1060 struct node *
1061 eval_asru(struct node *np)
1062 {
1063 	ASSERT(np->t == T_NAME);
1064 	return (np);
1065 }
1066