10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate * 260Sstevel@tonic-gate * eval.c -- constraint evaluation module 270Sstevel@tonic-gate * 280Sstevel@tonic-gate * this module evaluates constraints. 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <stdio.h> 340Sstevel@tonic-gate #include <stdlib.h> 350Sstevel@tonic-gate #include <ctype.h> 360Sstevel@tonic-gate #include <string.h> 370Sstevel@tonic-gate #include "alloc.h" 380Sstevel@tonic-gate #include "out.h" 390Sstevel@tonic-gate #include "stable.h" 400Sstevel@tonic-gate #include "literals.h" 410Sstevel@tonic-gate #include "lut.h" 420Sstevel@tonic-gate #include "tree.h" 430Sstevel@tonic-gate #include "ptree.h" 440Sstevel@tonic-gate #include "itree.h" 450Sstevel@tonic-gate #include "eval.h" 460Sstevel@tonic-gate #include "config.h" 470Sstevel@tonic-gate #include "platform.h" 480Sstevel@tonic-gate 490Sstevel@tonic-gate 500Sstevel@tonic-gate static struct node *eval_dup(struct node *np, struct lut *ex, 510Sstevel@tonic-gate struct node *epnames[]); 520Sstevel@tonic-gate 530Sstevel@tonic-gate /* 540Sstevel@tonic-gate * begins_with -- return true if rhs path begins with everything in lhs path 550Sstevel@tonic-gate */ 560Sstevel@tonic-gate static int 570Sstevel@tonic-gate begins_with(struct node *lhs, struct node *rhs) 580Sstevel@tonic-gate { 590Sstevel@tonic-gate int lnum; 600Sstevel@tonic-gate int rnum; 610Sstevel@tonic-gate 620Sstevel@tonic-gate if (lhs == NULL) 630Sstevel@tonic-gate return (1); /* yep -- it all matched */ 640Sstevel@tonic-gate 650Sstevel@tonic-gate if (rhs == NULL) 660Sstevel@tonic-gate return (0); /* nope, ran out of rhs first */ 670Sstevel@tonic-gate 680Sstevel@tonic-gate ASSERTeq(lhs->t, T_NAME, ptree_nodetype2str); 690Sstevel@tonic-gate ASSERTeq(rhs->t, T_NAME, ptree_nodetype2str); 700Sstevel@tonic-gate 710Sstevel@tonic-gate if (lhs->u.name.s != rhs->u.name.s) 720Sstevel@tonic-gate return (0); /* nope, different component names */ 730Sstevel@tonic-gate 740Sstevel@tonic-gate if (lhs->u.name.child && lhs->u.name.child->t == T_NUM) 750Sstevel@tonic-gate lnum = (int)lhs->u.name.child->u.ull; 760Sstevel@tonic-gate else 770Sstevel@tonic-gate out(O_DIE, "begins_with: unexpected lhs child"); 780Sstevel@tonic-gate 790Sstevel@tonic-gate if (rhs->u.name.child && rhs->u.name.child->t == T_NUM) 800Sstevel@tonic-gate rnum = (int)rhs->u.name.child->u.ull; 810Sstevel@tonic-gate else 820Sstevel@tonic-gate out(O_DIE, "begins_with: unexpected rhs child"); 830Sstevel@tonic-gate 840Sstevel@tonic-gate if (lnum != rnum) 850Sstevel@tonic-gate return (0); /* nope, instance numbers were different */ 860Sstevel@tonic-gate 870Sstevel@tonic-gate return (begins_with(lhs->u.name.next, rhs->u.name.next)); 880Sstevel@tonic-gate } 890Sstevel@tonic-gate 900Sstevel@tonic-gate /* 910Sstevel@tonic-gate * evaluate a variety of functions and place result in valuep. return 1 if 920Sstevel@tonic-gate * function evaluation was successful; 0 if otherwise (e.g., the case of an 930Sstevel@tonic-gate * invalid argument to the function) 940Sstevel@tonic-gate */ 950Sstevel@tonic-gate /*ARGSUSED*/ 960Sstevel@tonic-gate static int 970Sstevel@tonic-gate eval_func(struct node *funcnp, struct lut *ex, struct node *epnames[], 980Sstevel@tonic-gate struct node *np, struct lut **globals, 990Sstevel@tonic-gate struct config *croot, struct arrow *arrowp, int try, struct evalue *valuep) 1000Sstevel@tonic-gate { 1010Sstevel@tonic-gate const char *funcname = funcnp->u.func.s; 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate if (funcname == L_within) { 1040Sstevel@tonic-gate /* within()'s are not really constraints -- always true */ 1050Sstevel@tonic-gate valuep->t = UINT64; 1060Sstevel@tonic-gate valuep->v = 1; 1070Sstevel@tonic-gate return (1); 1080Sstevel@tonic-gate } else if (funcname == L_is_under) { 1090Sstevel@tonic-gate struct node *lhs; 1100Sstevel@tonic-gate struct node *rhs; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate if (np->u.expr.left->t == T_NAME) 1130Sstevel@tonic-gate lhs = np->u.expr.left; 1140Sstevel@tonic-gate else if (np->u.expr.left->u.func.s == L_fru) 1150Sstevel@tonic-gate lhs = eval_fru(np->u.expr.left->u.func.arglist); 1160Sstevel@tonic-gate else if (np->u.expr.left->u.func.s == L_asru) 1170Sstevel@tonic-gate lhs = eval_asru(np->u.expr.left->u.func.arglist); 1180Sstevel@tonic-gate else 1190Sstevel@tonic-gate out(O_DIE, "is_under: unexpected lhs type: %s", 1200Sstevel@tonic-gate ptree_nodetype2str(np->u.expr.left->t)); 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate if (np->u.expr.right->t == T_NAME) 1230Sstevel@tonic-gate rhs = np->u.expr.right; 1240Sstevel@tonic-gate else if (np->u.expr.right->u.func.s == L_fru) 1250Sstevel@tonic-gate rhs = eval_fru(np->u.expr.right->u.func.arglist); 1260Sstevel@tonic-gate else if (np->u.expr.right->u.func.s == L_asru) 1270Sstevel@tonic-gate rhs = eval_asru(np->u.expr.right->u.func.arglist); 1280Sstevel@tonic-gate else 1290Sstevel@tonic-gate out(O_DIE, "is_under: unexpected rhs type: %s", 1300Sstevel@tonic-gate ptree_nodetype2str(np->u.expr.right->t)); 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate /* eval_dup will expand wildcards, iterators, etc... */ 1330Sstevel@tonic-gate lhs = eval_dup(lhs, ex, epnames); 1340Sstevel@tonic-gate rhs = eval_dup(rhs, ex, epnames); 1350Sstevel@tonic-gate valuep->t = UINT64; 1360Sstevel@tonic-gate valuep->v = begins_with(lhs, rhs); 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate out(O_ALTFP|O_VERB2|O_NONL, "eval_func:is_under("); 1390Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, lhs); 1400Sstevel@tonic-gate out(O_ALTFP|O_VERB2|O_NONL, ","); 1410Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, rhs); 1420Sstevel@tonic-gate out(O_ALTFP|O_VERB2, ") returned %d", (int)valuep->v); 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate tree_free(lhs); 1450Sstevel@tonic-gate tree_free(rhs); 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate return (1); 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate if (try) 1510Sstevel@tonic-gate return (0); 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate if (funcname == L_fru) { 1540Sstevel@tonic-gate valuep->t = NODEPTR; 1550Sstevel@tonic-gate valuep->v = (unsigned long long)eval_fru(np); 1560Sstevel@tonic-gate return (1); 1570Sstevel@tonic-gate } else if (funcname == L_asru) { 1580Sstevel@tonic-gate valuep->t = NODEPTR; 1590Sstevel@tonic-gate valuep->v = (unsigned long long)eval_asru(np); 1600Sstevel@tonic-gate return (1); 1610Sstevel@tonic-gate } else if (funcname == L_call) { 1620Sstevel@tonic-gate return (! platform_call(np, globals, croot, arrowp, valuep)); 1630Sstevel@tonic-gate } else if (funcname == L_is_connected) { 1640Sstevel@tonic-gate return (! config_is_connected(np, croot, valuep)); 1650Sstevel@tonic-gate } else if (funcname == L_is_on) { 1660Sstevel@tonic-gate return (! config_is_on(np, croot, valuep)); 1670Sstevel@tonic-gate } else if (funcname == L_is_present) { 1680Sstevel@tonic-gate return (! config_is_present(np, croot, valuep)); 1690Sstevel@tonic-gate } else if (funcname == L_is_type) { 1700Sstevel@tonic-gate return (! config_is_type(np, croot, valuep)); 1710Sstevel@tonic-gate } else if (funcname == L_confprop) { 1720Sstevel@tonic-gate return (! config_confprop(np, croot, valuep)); 1730Sstevel@tonic-gate } else if (funcname == L_envprop) { 1740Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 1750Sstevel@tonic-gate "eval_func: %s not yet supported", funcname); 1760Sstevel@tonic-gate } else if (funcname == L_payloadprop) { 1770Sstevel@tonic-gate outfl(O_ALTFP|O_VERB|O_NONL, np->file, np->line, 1780Sstevel@tonic-gate "payloadprop(\"%s\") ", np->u.quote.s); 1790Sstevel@tonic-gate if (funcnp->u.func.cachedval != NULL) { 1800Sstevel@tonic-gate *valuep = *(struct evalue *)(funcnp->u.func.cachedval); 181*186Sdb35262 182*186Sdb35262 switch (valuep->t) { 183*186Sdb35262 case UINT64: 184*186Sdb35262 case NODEPTR: 185*186Sdb35262 out(O_ALTFP|O_VERB, "cached: %llu", valuep->v); 186*186Sdb35262 break; 187*186Sdb35262 case STRING: 188*186Sdb35262 out(O_ALTFP|O_VERB, "cached: \"%s\"", 189*186Sdb35262 (char *)valuep->v); 190*186Sdb35262 break; 191*186Sdb35262 default: 192*186Sdb35262 out(O_ALTFP|O_VERB, "undefined"); 193*186Sdb35262 break; 194*186Sdb35262 } 195*186Sdb35262 1960Sstevel@tonic-gate return (1); 1970Sstevel@tonic-gate } else if (platform_payloadprop(np, valuep)) { 1980Sstevel@tonic-gate /* platform_payloadprop() returned false, pass it on */ 1990Sstevel@tonic-gate out(O_ALTFP|O_VERB, "failed."); 2000Sstevel@tonic-gate return (0); 2010Sstevel@tonic-gate } else { 2020Sstevel@tonic-gate /* got back true, cache the value */ 2030Sstevel@tonic-gate funcnp->u.func.cachedval = 2040Sstevel@tonic-gate MALLOC(sizeof (struct evalue)); 2050Sstevel@tonic-gate *(struct evalue *)(funcnp->u.func.cachedval) = 2060Sstevel@tonic-gate *valuep; 207*186Sdb35262 208*186Sdb35262 switch (valuep->t) { 209*186Sdb35262 case UINT64: 210*186Sdb35262 case NODEPTR: 211*186Sdb35262 out(O_ALTFP|O_VERB, "cached: %llu", valuep->v); 212*186Sdb35262 break; 213*186Sdb35262 case STRING: 214*186Sdb35262 out(O_ALTFP|O_VERB, "cached: \"%s\"", 215*186Sdb35262 (char *)valuep->v); 216*186Sdb35262 break; 217*186Sdb35262 default: 218*186Sdb35262 out(O_ALTFP|O_VERB, "undefined"); 219*186Sdb35262 break; 220*186Sdb35262 } 221*186Sdb35262 2220Sstevel@tonic-gate return (1); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate } else 2250Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 2260Sstevel@tonic-gate "eval_func: unexpected func: %s", funcname); 2270Sstevel@tonic-gate /*NOTREACHED*/ 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate static struct node * 2310Sstevel@tonic-gate eval_wildcardedname(struct node *np, struct lut *ex, struct node *epnames[]) 2320Sstevel@tonic-gate { 2330Sstevel@tonic-gate struct node *npstart, *npend, *npref, *newnp; 2340Sstevel@tonic-gate struct node *np1, *np2, *retp; 2350Sstevel@tonic-gate int i; 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate if (epnames == NULL || epnames[0] == NULL) 2380Sstevel@tonic-gate return (NULL); 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate for (i = 0; epnames[i] != NULL; i++) { 2410Sstevel@tonic-gate if (tree_namecmp(np, epnames[i]) == 0) 2420Sstevel@tonic-gate return (NULL); 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate /* 2460Sstevel@tonic-gate * get to this point if np does not match any of the entries in 2470Sstevel@tonic-gate * epnames. check if np is a path that must preceded by a wildcard 2480Sstevel@tonic-gate * portion. for this case we must first determine which epnames[] 2490Sstevel@tonic-gate * entry should be used for wildcarding. 2500Sstevel@tonic-gate */ 2510Sstevel@tonic-gate npstart = NULL; 2520Sstevel@tonic-gate for (i = 0; epnames[i] != NULL; i++) { 2530Sstevel@tonic-gate for (npref = epnames[i]; npref; npref = npref->u.name.next) { 2540Sstevel@tonic-gate if (npref->u.name.s == np->u.name.s) { 2550Sstevel@tonic-gate for (np1 = npref, np2 = np; 2560Sstevel@tonic-gate np1 != NULL && np2 != NULL; 2570Sstevel@tonic-gate np1 = np1->u.name.next, 2580Sstevel@tonic-gate np2 = np2->u.name.next) { 2590Sstevel@tonic-gate if (np1->u.name.s != np2->u.name.s) 2600Sstevel@tonic-gate break; 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate if (np2 == NULL) { 2630Sstevel@tonic-gate npstart = epnames[i]; 2640Sstevel@tonic-gate npend = npref; 2650Sstevel@tonic-gate if (np1 == NULL) 2660Sstevel@tonic-gate break; 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate if (npstart != NULL) 2720Sstevel@tonic-gate break; 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate if (npstart == NULL) { 2760Sstevel@tonic-gate /* no match; np is not a path to be wildcarded */ 2770Sstevel@tonic-gate return (NULL); 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate /* 2810Sstevel@tonic-gate * dup (npstart -- npend) which is the wildcarded portion. all 2820Sstevel@tonic-gate * children should be T_NUMs. 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gate retp = NULL; 2850Sstevel@tonic-gate for (npref = npstart; 2860Sstevel@tonic-gate ! (npref == NULL || npref == npend); 2870Sstevel@tonic-gate npref = npref->u.name.next) { 2880Sstevel@tonic-gate newnp = newnode(T_NAME, np->file, np->line); 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate newnp->u.name.t = npref->u.name.t; 2910Sstevel@tonic-gate newnp->u.name.s = npref->u.name.s; 2920Sstevel@tonic-gate newnp->u.name.last = newnp; 2930Sstevel@tonic-gate newnp->u.name.it = npref->u.name.it; 2940Sstevel@tonic-gate newnp->u.name.cp = npref->u.name.cp; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate ASSERT(npref->u.name.child != NULL); 2970Sstevel@tonic-gate ASSERT(npref->u.name.child->t == T_NUM); 2980Sstevel@tonic-gate newnp->u.name.child = newnode(T_NUM, np->file, np->line); 2990Sstevel@tonic-gate newnp->u.name.child->u.ull = npref->u.name.child->u.ull; 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate if (retp == NULL) { 3020Sstevel@tonic-gate retp = newnp; 3030Sstevel@tonic-gate } else { 3040Sstevel@tonic-gate retp->u.name.last->u.name.next = newnp; 3050Sstevel@tonic-gate retp->u.name.last = newnp; 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate ASSERT(retp != NULL); 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate /* now append the nonwildcarded portion */ 3120Sstevel@tonic-gate retp = tree_name_append(retp, eval_dup(np, ex, NULL)); 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate return (retp); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate static struct node * 3180Sstevel@tonic-gate eval_dup(struct node *np, struct lut *ex, struct node *epnames[]) 3190Sstevel@tonic-gate { 3200Sstevel@tonic-gate struct node *newnp; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate if (np == NULL) 3230Sstevel@tonic-gate return (NULL); 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate switch (np->t) { 3260Sstevel@tonic-gate case T_GLOBID: 3270Sstevel@tonic-gate return (tree_globid(np->u.globid.s, np->file, np->line)); 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate case T_ASSIGN: 3300Sstevel@tonic-gate case T_CONDIF: 3310Sstevel@tonic-gate case T_CONDELSE: 3320Sstevel@tonic-gate case T_NE: 3330Sstevel@tonic-gate case T_EQ: 3340Sstevel@tonic-gate case T_LT: 3350Sstevel@tonic-gate case T_LE: 3360Sstevel@tonic-gate case T_GT: 3370Sstevel@tonic-gate case T_GE: 3380Sstevel@tonic-gate case T_BITAND: 3390Sstevel@tonic-gate case T_BITOR: 3400Sstevel@tonic-gate case T_BITXOR: 3410Sstevel@tonic-gate case T_BITNOT: 3420Sstevel@tonic-gate case T_LSHIFT: 3430Sstevel@tonic-gate case T_RSHIFT: 3440Sstevel@tonic-gate case T_LIST: 3450Sstevel@tonic-gate case T_AND: 3460Sstevel@tonic-gate case T_OR: 3470Sstevel@tonic-gate case T_NOT: 3480Sstevel@tonic-gate case T_ADD: 3490Sstevel@tonic-gate case T_SUB: 3500Sstevel@tonic-gate case T_MUL: 3510Sstevel@tonic-gate case T_DIV: 3520Sstevel@tonic-gate case T_MOD: 3530Sstevel@tonic-gate return (tree_expr(np->t, 3540Sstevel@tonic-gate eval_dup(np->u.expr.left, ex, epnames), 3550Sstevel@tonic-gate eval_dup(np->u.expr.right, ex, epnames))); 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate case T_NAME: { 3580Sstevel@tonic-gate struct iterinfo *iterinfop; 3590Sstevel@tonic-gate struct node *newchild = NULL; 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL); 3620Sstevel@tonic-gate if (iterinfop != NULL) { 3630Sstevel@tonic-gate /* explicit iterator; not part of pathname */ 3640Sstevel@tonic-gate newnp = newnode(T_NUM, np->file, np->line); 3650Sstevel@tonic-gate newnp->u.ull = iterinfop->num; 3660Sstevel@tonic-gate return (newnp); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /* see if np is a path with wildcard portion */ 3700Sstevel@tonic-gate newnp = eval_wildcardedname(np, ex, epnames); 3710Sstevel@tonic-gate if (newnp != NULL) 3720Sstevel@tonic-gate return (newnp); 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate /* turn off wildcarding for child */ 3750Sstevel@tonic-gate newchild = eval_dup(np->u.name.child, ex, NULL); 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate if (newchild != NULL) { 3780Sstevel@tonic-gate if (newchild->t != T_NUM) { 3790Sstevel@tonic-gate /* 3800Sstevel@tonic-gate * not a number, eh? we must resolve this 3810Sstevel@tonic-gate * to a number. 3820Sstevel@tonic-gate */ 3830Sstevel@tonic-gate struct evalue value; 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate if (eval_expr(newchild, ex, epnames, 3860Sstevel@tonic-gate NULL, NULL, NULL, 1, &value) == 0 || 3870Sstevel@tonic-gate value.t != UINT64) { 3880Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 3890Sstevel@tonic-gate "eval_dup: could not resolve " 3900Sstevel@tonic-gate "iterator of %s", np->u.name.s); 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate tree_free(newchild); 3940Sstevel@tonic-gate newchild = newnode(T_NUM, np->file, np->line); 3950Sstevel@tonic-gate newchild->u.ull = value.v; 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate newnp = newnode(np->t, np->file, np->line); 3990Sstevel@tonic-gate newnp->u.name.s = np->u.name.s; 4000Sstevel@tonic-gate newnp->u.name.it = np->u.name.it; 4010Sstevel@tonic-gate newnp->u.name.cp = np->u.name.cp; 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate newnp->u.name.last = newnp; 4040Sstevel@tonic-gate newnp->u.name.child = newchild; 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate if (np->u.name.next != NULL) { 4070Sstevel@tonic-gate /* turn off wildcarding for next */ 4080Sstevel@tonic-gate return (tree_name_append(newnp, 4090Sstevel@tonic-gate eval_dup(np->u.name.next, ex, NULL))); 4100Sstevel@tonic-gate } else { 4110Sstevel@tonic-gate return (newnp); 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate } else { 4140Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 4150Sstevel@tonic-gate "eval_dup: internal error: \"%s\" is neither " 4160Sstevel@tonic-gate "an iterator nor a pathname", np->u.name.s); 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate /*NOTREACHED*/ 4190Sstevel@tonic-gate break; 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate case T_FUNC: 4230Sstevel@tonic-gate return (tree_func(np->u.func.s, 4240Sstevel@tonic-gate eval_dup(np->u.func.arglist, ex, epnames), 4250Sstevel@tonic-gate np->file, np->line)); 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate case T_QUOTE: 4280Sstevel@tonic-gate newnp = newnode(T_QUOTE, np->file, np->line); 4290Sstevel@tonic-gate newnp->u.quote.s = np->u.quote.s; 4300Sstevel@tonic-gate return (newnp); 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate case T_NUM: 4330Sstevel@tonic-gate newnp = newnode(T_NUM, np->file, np->line); 4340Sstevel@tonic-gate newnp->u.ull = np->u.ull; 4350Sstevel@tonic-gate return (newnp); 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate default: 4380Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 4390Sstevel@tonic-gate "eval_dup: unexpected node type: %s", 4400Sstevel@tonic-gate ptree_nodetype2str(np->t)); 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate /*NOTREACHED*/ 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate /* 4460Sstevel@tonic-gate * eval_potential -- see if constraint is potentially true 4470Sstevel@tonic-gate * 4480Sstevel@tonic-gate * this function is used at instance tree creation time to see if 4490Sstevel@tonic-gate * any constraints are already known to be false. if this function 4500Sstevel@tonic-gate * returns false, then the constraint will always be false and there's 4510Sstevel@tonic-gate * no need to include the propagation arrow in the instance tree. 4520Sstevel@tonic-gate * 4530Sstevel@tonic-gate * if this routine returns true, either the constraint is known to 4540Sstevel@tonic-gate * be always true (so there's no point in attaching the constraint 4550Sstevel@tonic-gate * to the propagation arrow in the instance tree), or the constraint 4560Sstevel@tonic-gate * contains "deferred" expressions like global variables or poller calls 4570Sstevel@tonic-gate * and so it must be evaluated during calls to fme_eval(). in this last 4580Sstevel@tonic-gate * case, where a constraint needs to be attached to the propagation arrow 4590Sstevel@tonic-gate * in the instance tree, this routine returns a newly created constraint 4600Sstevel@tonic-gate * in *newc where all the non-deferred things have been filled in. 4610Sstevel@tonic-gate * 4620Sstevel@tonic-gate * so in summary: 4630Sstevel@tonic-gate * 4640Sstevel@tonic-gate * return of false: constraint can never be true, *newc will be NULL. 4650Sstevel@tonic-gate * 4660Sstevel@tonic-gate * return of true with *newc unchanged: constraint will always be true. 4670Sstevel@tonic-gate * 4680Sstevel@tonic-gate * return of true with *newc changed: use new constraint in *newc. 4690Sstevel@tonic-gate * 4700Sstevel@tonic-gate * the lookup table for all explicit iterators, ex, is passed in. 4710Sstevel@tonic-gate * 4720Sstevel@tonic-gate * *newc can either be NULL on entry, or if can contain constraints from 4730Sstevel@tonic-gate * previous calls to eval_potential() (i.e. for building up an instance 4740Sstevel@tonic-gate * tree constraint from several potential constraints). if *newc already 4750Sstevel@tonic-gate * contains constraints, anything added to it will be joined by adding 4760Sstevel@tonic-gate * a T_AND node at the top of *newc. 4770Sstevel@tonic-gate */ 4780Sstevel@tonic-gate int 4790Sstevel@tonic-gate eval_potential(struct node *np, struct lut *ex, struct node *epnames[], 4800Sstevel@tonic-gate struct node **newc) 4810Sstevel@tonic-gate { 4820Sstevel@tonic-gate struct node *newnp; 4830Sstevel@tonic-gate struct evalue value; 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate if (eval_expr(np, ex, epnames, NULL, NULL, NULL, 1, &value) == 0) { 4860Sstevel@tonic-gate /* 4870Sstevel@tonic-gate * couldn't eval expression because 4880Sstevel@tonic-gate * it contains deferred items. make 4890Sstevel@tonic-gate * a duplicate expression with all the 4900Sstevel@tonic-gate * non-deferred items expanded. 4910Sstevel@tonic-gate */ 4920Sstevel@tonic-gate newnp = eval_dup(np, ex, epnames); 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate if (*newc == NULL) { 4950Sstevel@tonic-gate /* 4960Sstevel@tonic-gate * constraint is potentially true if deferred 4970Sstevel@tonic-gate * expression in newnp is true. *newc was NULL 4980Sstevel@tonic-gate * so new constraint is just the one in newnp. 4990Sstevel@tonic-gate */ 5000Sstevel@tonic-gate *newc = newnp; 5010Sstevel@tonic-gate return (1); 5020Sstevel@tonic-gate } else { 5030Sstevel@tonic-gate /* 5040Sstevel@tonic-gate * constraint is potentially true if deferred 5050Sstevel@tonic-gate * expression in newnp is true. *newc already 5060Sstevel@tonic-gate * contained a constraint so add an AND with the 5070Sstevel@tonic-gate * constraint in newnp. 5080Sstevel@tonic-gate */ 5090Sstevel@tonic-gate *newc = tree_expr(T_AND, *newc, newnp); 5100Sstevel@tonic-gate return (1); 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate } else if (value.t == UNDEFINED) { 5130Sstevel@tonic-gate /* constraint can never be true */ 5140Sstevel@tonic-gate return (0); 5150Sstevel@tonic-gate } else if (value.t == UINT64 && value.v == 0) { 5160Sstevel@tonic-gate /* constraint can never be true */ 5170Sstevel@tonic-gate return (0); 5180Sstevel@tonic-gate } else { 5190Sstevel@tonic-gate /* constraint is always true (nothing deferred to eval) */ 5200Sstevel@tonic-gate return (1); 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate static int 5250Sstevel@tonic-gate check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype, 5260Sstevel@tonic-gate struct node *np) 5270Sstevel@tonic-gate { 5280Sstevel@tonic-gate if (dtype != UNDEFINED && lp->t != dtype) { 5290Sstevel@tonic-gate outfl(O_OK, np->file, np->line, 5300Sstevel@tonic-gate "invalid datatype of argument for operation %s", 5310Sstevel@tonic-gate ptree_nodetype2str(np->t)); 5320Sstevel@tonic-gate return (1); 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate if (rp != NULL && lp->t != rp->t) { 5360Sstevel@tonic-gate outfl(O_OK, np->file, np->line, 5370Sstevel@tonic-gate "mismatch in datatype of arguments for operation %s", 5380Sstevel@tonic-gate ptree_nodetype2str(np->t)); 5390Sstevel@tonic-gate return (1); 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate return (0); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate /* 5460Sstevel@tonic-gate * eval_expr -- evaluate expression into *valuep 5470Sstevel@tonic-gate * 5480Sstevel@tonic-gate * the meaning of the return value depends on the input value of try. 5490Sstevel@tonic-gate * 5500Sstevel@tonic-gate * for try == 1: if any deferred items are encounted, bail out and return 5510Sstevel@tonic-gate * false. returns true if we made it through entire expression without 5520Sstevel@tonic-gate * hitting any deferred items. 5530Sstevel@tonic-gate * 5540Sstevel@tonic-gate * for try == 0: return true if all operations were performed successfully. 5550Sstevel@tonic-gate * return false if otherwise. for example, any of the following conditions 5560Sstevel@tonic-gate * will result in a false return value: 5570Sstevel@tonic-gate * - attempted use of an uninitialized global variable 5580Sstevel@tonic-gate * - failure in function evaluation 5590Sstevel@tonic-gate * - illegal arithmetic operation (argument out of range) 5600Sstevel@tonic-gate */ 5610Sstevel@tonic-gate int 5620Sstevel@tonic-gate eval_expr(struct node *np, struct lut *ex, struct node *epnames[], 5630Sstevel@tonic-gate struct lut **globals, struct config *croot, struct arrow *arrowp, 5640Sstevel@tonic-gate int try, struct evalue *valuep) 5650Sstevel@tonic-gate { 5660Sstevel@tonic-gate struct evalue *gval; 5670Sstevel@tonic-gate struct evalue lval; 5680Sstevel@tonic-gate struct evalue rval; 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate if (np == NULL) { 5710Sstevel@tonic-gate valuep->t = UINT64; 5720Sstevel@tonic-gate valuep->v = 1; /* no constraint means "true" */ 5730Sstevel@tonic-gate return (1); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate valuep->t = UNDEFINED; 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate switch (np->t) { 5790Sstevel@tonic-gate case T_GLOBID: 5800Sstevel@tonic-gate if (try) 5810Sstevel@tonic-gate return (0); 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate /* 5840Sstevel@tonic-gate * only handle case of getting (and not setting) the value 5850Sstevel@tonic-gate * of a global variable 5860Sstevel@tonic-gate */ 5870Sstevel@tonic-gate gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL); 5880Sstevel@tonic-gate if (gval == NULL) { 5890Sstevel@tonic-gate valuep->t = UNDEFINED; 5900Sstevel@tonic-gate return (0); 5910Sstevel@tonic-gate } else { 5920Sstevel@tonic-gate valuep->t = gval->t; 5930Sstevel@tonic-gate valuep->v = gval->v; 5940Sstevel@tonic-gate return (1); 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate case T_ASSIGN: 5980Sstevel@tonic-gate if (try) 5990Sstevel@tonic-gate return (0); 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate /* 6020Sstevel@tonic-gate * first evaluate rhs, then try to store value in lhs which 6030Sstevel@tonic-gate * should be a global variable 6040Sstevel@tonic-gate */ 6050Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 6060Sstevel@tonic-gate arrowp, try, &rval)) 6070Sstevel@tonic-gate return (0); 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate ASSERT(np->u.expr.left->t == T_GLOBID); 6100Sstevel@tonic-gate gval = lut_lookup(*globals, 6110Sstevel@tonic-gate (void *)np->u.expr.left->u.globid.s, NULL); 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate if (gval == NULL) { 6140Sstevel@tonic-gate gval = MALLOC(sizeof (*gval)); 6150Sstevel@tonic-gate *globals = lut_add(*globals, 6160Sstevel@tonic-gate (void *) np->u.expr.left->u.globid.s, 6170Sstevel@tonic-gate gval, NULL); 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate gval->t = rval.t; 6210Sstevel@tonic-gate gval->v = rval.v; 6220Sstevel@tonic-gate valuep->t = rval.t; 6230Sstevel@tonic-gate valuep->v = rval.v; 6240Sstevel@tonic-gate return (1); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate case T_EQ: 6270Sstevel@tonic-gate #define IMPLICIT_ASSIGN_IN_EQ 6280Sstevel@tonic-gate #ifdef IMPLICIT_ASSIGN_IN_EQ 6290Sstevel@tonic-gate /* 6300Sstevel@tonic-gate * if lhs is an uninitialized global variable, perform 6310Sstevel@tonic-gate * an assignment. 6320Sstevel@tonic-gate * 6330Sstevel@tonic-gate * one insidious side effect of implicit assignment is 6340Sstevel@tonic-gate * that the "==" operator does not return a Boolean if 6350Sstevel@tonic-gate * implicit assignment was performed. 6360Sstevel@tonic-gate */ 6370Sstevel@tonic-gate if (try == 0 && 6380Sstevel@tonic-gate np->u.expr.left->t == T_GLOBID && 6390Sstevel@tonic-gate (gval = lut_lookup(*globals, 6400Sstevel@tonic-gate (void *)np->u.expr.left->u.globid.s, NULL)) == NULL) { 6410Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, 6420Sstevel@tonic-gate croot, arrowp, try, &rval)) 6430Sstevel@tonic-gate return (0); 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate gval = MALLOC(sizeof (*gval)); 6460Sstevel@tonic-gate *globals = lut_add(*globals, 6470Sstevel@tonic-gate (void *) np->u.expr.left->u.globid.s, 6480Sstevel@tonic-gate gval, NULL); 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate gval->t = rval.t; 6510Sstevel@tonic-gate gval->v = rval.v; 6520Sstevel@tonic-gate valuep->t = rval.t; 6530Sstevel@tonic-gate valuep->v = rval.v; 6540Sstevel@tonic-gate return (1); 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate #endif /* IMPLICIT_ASSIGN_IN_EQ */ 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 6590Sstevel@tonic-gate arrowp, try, &lval)) 6600Sstevel@tonic-gate return (0); 6610Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 6620Sstevel@tonic-gate arrowp, try, &rval)) 6630Sstevel@tonic-gate return (0); 6640Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UNDEFINED, np)) 6650Sstevel@tonic-gate return (0); 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate valuep->t = UINT64; 6680Sstevel@tonic-gate valuep->v = (lval.v == rval.v); 6690Sstevel@tonic-gate return (1); 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate case T_LT: 6720Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 6730Sstevel@tonic-gate arrowp, try, &lval)) 6740Sstevel@tonic-gate return (0); 6750Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 6760Sstevel@tonic-gate arrowp, try, &rval)) 6770Sstevel@tonic-gate return (0); 6780Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UNDEFINED, np)) 6790Sstevel@tonic-gate return (0); 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate valuep->t = UINT64; 6820Sstevel@tonic-gate valuep->v = (lval.v < rval.v); 6830Sstevel@tonic-gate return (1); 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate case T_LE: 6860Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 6870Sstevel@tonic-gate arrowp, try, &lval)) 6880Sstevel@tonic-gate return (0); 6890Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 6900Sstevel@tonic-gate arrowp, try, &rval)) 6910Sstevel@tonic-gate return (0); 6920Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UNDEFINED, np)) 6930Sstevel@tonic-gate return (0); 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate valuep->t = UINT64; 6960Sstevel@tonic-gate valuep->v = (lval.v <= rval.v); 6970Sstevel@tonic-gate return (1); 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate case T_GT: 7000Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 7010Sstevel@tonic-gate arrowp, try, &lval)) 7020Sstevel@tonic-gate return (0); 7030Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 7040Sstevel@tonic-gate arrowp, try, &rval)) 7050Sstevel@tonic-gate return (0); 7060Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UNDEFINED, np)) 7070Sstevel@tonic-gate return (0); 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate valuep->t = UINT64; 7100Sstevel@tonic-gate valuep->v = (lval.v > rval.v); 7110Sstevel@tonic-gate return (1); 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate case T_GE: 7140Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 7150Sstevel@tonic-gate arrowp, try, &lval)) 7160Sstevel@tonic-gate return (0); 7170Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 7180Sstevel@tonic-gate arrowp, try, &rval)) 7190Sstevel@tonic-gate return (0); 7200Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UNDEFINED, np)) 7210Sstevel@tonic-gate return (0); 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate valuep->t = UINT64; 7240Sstevel@tonic-gate valuep->v = (lval.v >= rval.v); 7250Sstevel@tonic-gate return (1); 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate case T_BITAND: 7280Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 7290Sstevel@tonic-gate arrowp, try, &lval)) 7300Sstevel@tonic-gate return (0); 7310Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 7320Sstevel@tonic-gate arrowp, try, &rval)) 7330Sstevel@tonic-gate return (0); 7340Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 7350Sstevel@tonic-gate return (0); 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate valuep->t = lval.t; 7380Sstevel@tonic-gate valuep->v = (lval.v & rval.v); 7390Sstevel@tonic-gate return (1); 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate case T_BITOR: 7420Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 7430Sstevel@tonic-gate arrowp, try, &lval)) 7440Sstevel@tonic-gate return (0); 7450Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 7460Sstevel@tonic-gate arrowp, try, &rval)) 7470Sstevel@tonic-gate return (0); 7480Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 7490Sstevel@tonic-gate return (0); 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate valuep->t = lval.t; 7520Sstevel@tonic-gate valuep->v = (lval.v | rval.v); 7530Sstevel@tonic-gate return (1); 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate case T_BITXOR: 7560Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 7570Sstevel@tonic-gate arrowp, try, &lval)) 7580Sstevel@tonic-gate return (0); 7590Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 7600Sstevel@tonic-gate arrowp, try, &rval)) 7610Sstevel@tonic-gate return (0); 7620Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 7630Sstevel@tonic-gate return (0); 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate valuep->t = lval.t; 7660Sstevel@tonic-gate valuep->v = (lval.v ^ rval.v); 7670Sstevel@tonic-gate return (1); 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate case T_BITNOT: 7700Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 7710Sstevel@tonic-gate arrowp, try, &lval)) 7720Sstevel@tonic-gate return (0); 7730Sstevel@tonic-gate ASSERT(np->u.expr.right == NULL); 7740Sstevel@tonic-gate if (check_expr_args(&lval, NULL, UINT64, np)) 7750Sstevel@tonic-gate return (0); 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate valuep->t = UINT64; 7780Sstevel@tonic-gate valuep->v = ~ lval.v; 7790Sstevel@tonic-gate return (1); 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate case T_LSHIFT: 7820Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 7830Sstevel@tonic-gate arrowp, try, &lval)) 7840Sstevel@tonic-gate return (0); 7850Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 7860Sstevel@tonic-gate arrowp, try, &rval)) 7870Sstevel@tonic-gate return (0); 7880Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 7890Sstevel@tonic-gate return (0); 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate valuep->t = UINT64; 7920Sstevel@tonic-gate valuep->v = (lval.v << rval.v); 7930Sstevel@tonic-gate return (1); 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate case T_RSHIFT: 7960Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 7970Sstevel@tonic-gate arrowp, try, &lval)) 7980Sstevel@tonic-gate return (0); 7990Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 8000Sstevel@tonic-gate arrowp, try, &rval)) 8010Sstevel@tonic-gate return (0); 8020Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 8030Sstevel@tonic-gate return (0); 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate valuep->t = UINT64; 8060Sstevel@tonic-gate valuep->v = (lval.v >> rval.v); 8070Sstevel@tonic-gate return (1); 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate case T_CONDIF: { 8100Sstevel@tonic-gate struct node *retnp; 8110Sstevel@tonic-gate int dotrue = 0; 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate /* 8140Sstevel@tonic-gate * evaluate 8150Sstevel@tonic-gate * expression ? stmtA [ : stmtB ] 8160Sstevel@tonic-gate * 8170Sstevel@tonic-gate * first see if expression is true or false, then determine 8180Sstevel@tonic-gate * if stmtA (or stmtB, if it exists) should be evaluated. 8190Sstevel@tonic-gate * 8200Sstevel@tonic-gate * "dotrue = 1" means stmtA should be evaluated. 8210Sstevel@tonic-gate */ 8220Sstevel@tonic-gate if (eval_expr(np->u.expr.left, ex, epnames, globals, croot, 8230Sstevel@tonic-gate arrowp, try, &lval) && 8240Sstevel@tonic-gate lval.t != UNDEFINED && lval.v != 0) 8250Sstevel@tonic-gate dotrue = 1; 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate ASSERT(np->u.expr.right != NULL); 8280Sstevel@tonic-gate if (np->u.expr.right->t == T_CONDELSE) { 8290Sstevel@tonic-gate if (dotrue) 8300Sstevel@tonic-gate retnp = np->u.expr.right->u.expr.left; 8310Sstevel@tonic-gate else 8320Sstevel@tonic-gate retnp = np->u.expr.right->u.expr.right; 8330Sstevel@tonic-gate } else { 8340Sstevel@tonic-gate /* no ELSE clause */ 8350Sstevel@tonic-gate if (dotrue) 8360Sstevel@tonic-gate retnp = np->u.expr.right; 8370Sstevel@tonic-gate else { 8380Sstevel@tonic-gate valuep->t = UINT64; 8390Sstevel@tonic-gate valuep->v = 0; 8400Sstevel@tonic-gate return (0); 8410Sstevel@tonic-gate } 8420Sstevel@tonic-gate } 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate if (!eval_expr(retnp, ex, epnames, globals, croot, 8450Sstevel@tonic-gate arrowp, try, valuep)) 8460Sstevel@tonic-gate return (0); 8470Sstevel@tonic-gate return (1); 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate case T_CONDELSE: 8510Sstevel@tonic-gate /* 8520Sstevel@tonic-gate * shouldn't get here, since T_CONDELSE is supposed to be 8530Sstevel@tonic-gate * evaluated as part of T_CONDIF 8540Sstevel@tonic-gate */ 8550Sstevel@tonic-gate out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s", 8560Sstevel@tonic-gate ptree_nodetype2str(np->t)); 8570Sstevel@tonic-gate return (0); 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate case T_NE: 8600Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 8610Sstevel@tonic-gate arrowp, try, &lval)) 8620Sstevel@tonic-gate return (0); 8630Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 8640Sstevel@tonic-gate arrowp, try, &rval)) 8650Sstevel@tonic-gate return (0); 8660Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UNDEFINED, np)) 8670Sstevel@tonic-gate return (0); 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate valuep->t = UINT64; 8700Sstevel@tonic-gate valuep->v = (lval.v != rval.v); 8710Sstevel@tonic-gate return (1); 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate case T_LIST: 8740Sstevel@tonic-gate case T_AND: 8750Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 8760Sstevel@tonic-gate arrowp, try, valuep)) 8770Sstevel@tonic-gate return (0); 8780Sstevel@tonic-gate if (valuep->v == 0) { 8790Sstevel@tonic-gate valuep->t = UINT64; 8800Sstevel@tonic-gate return (1); 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 8830Sstevel@tonic-gate arrowp, try, valuep)) 8840Sstevel@tonic-gate return (0); 8850Sstevel@tonic-gate valuep->t = UINT64; 8860Sstevel@tonic-gate valuep->v = valuep->v == 0 ? 0 : 1; 8870Sstevel@tonic-gate return (1); 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate case T_OR: 8900Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 8910Sstevel@tonic-gate arrowp, try, valuep)) 8920Sstevel@tonic-gate return (0); 8930Sstevel@tonic-gate if (valuep->v != 0) { 8940Sstevel@tonic-gate valuep->t = UINT64; 8950Sstevel@tonic-gate valuep->v = 1; 8960Sstevel@tonic-gate return (1); 8970Sstevel@tonic-gate } 8980Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 8990Sstevel@tonic-gate arrowp, try, valuep)) 9000Sstevel@tonic-gate return (0); 9010Sstevel@tonic-gate valuep->t = UINT64; 9020Sstevel@tonic-gate valuep->v = valuep->v == 0 ? 0 : 1; 9030Sstevel@tonic-gate return (1); 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate case T_NOT: 9060Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 9070Sstevel@tonic-gate arrowp, try, valuep)) 9080Sstevel@tonic-gate return (0); 9090Sstevel@tonic-gate valuep->t = UINT64; 9100Sstevel@tonic-gate valuep->v = ! valuep->v; 9110Sstevel@tonic-gate return (1); 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate case T_ADD: 9140Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 9150Sstevel@tonic-gate arrowp, try, &lval)) 9160Sstevel@tonic-gate return (0); 9170Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 9180Sstevel@tonic-gate arrowp, try, &rval)) 9190Sstevel@tonic-gate return (0); 9200Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 9210Sstevel@tonic-gate return (0); 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate valuep->t = lval.t; 9240Sstevel@tonic-gate valuep->v = lval.v + rval.v; 9250Sstevel@tonic-gate return (1); 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate case T_SUB: 9280Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 9290Sstevel@tonic-gate arrowp, try, &lval)) 9300Sstevel@tonic-gate return (0); 9310Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 9320Sstevel@tonic-gate arrowp, try, &rval)) 9330Sstevel@tonic-gate return (0); 9340Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 9350Sstevel@tonic-gate return (0); 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate /* since valuep is unsigned, return false if lval.v < rval.v */ 9380Sstevel@tonic-gate if (lval.v < rval.v) { 9390Sstevel@tonic-gate out(O_ERR, "eval_expr: T_SUB result is out of range"); 9400Sstevel@tonic-gate valuep->t = UNDEFINED; 9410Sstevel@tonic-gate return (0); 9420Sstevel@tonic-gate } 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate valuep->t = lval.t; 9450Sstevel@tonic-gate valuep->v = lval.v - rval.v; 9460Sstevel@tonic-gate return (1); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate case T_MUL: 9490Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 9500Sstevel@tonic-gate arrowp, try, &lval)) 9510Sstevel@tonic-gate return (0); 9520Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 9530Sstevel@tonic-gate arrowp, try, &rval)) 9540Sstevel@tonic-gate return (0); 9550Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 9560Sstevel@tonic-gate return (0); 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate valuep->t = lval.t; 9590Sstevel@tonic-gate valuep->v = lval.v * rval.v; 9600Sstevel@tonic-gate return (1); 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate case T_DIV: 9630Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 9640Sstevel@tonic-gate arrowp, try, &lval)) 9650Sstevel@tonic-gate return (0); 9660Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 9670Sstevel@tonic-gate arrowp, try, &rval)) 9680Sstevel@tonic-gate return (0); 9690Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 9700Sstevel@tonic-gate return (0); 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate /* return false if dividing by zero */ 9730Sstevel@tonic-gate if (rval.v == 0) { 9740Sstevel@tonic-gate out(O_ERR, "eval_expr: T_DIV division by zero"); 9750Sstevel@tonic-gate valuep->t = UNDEFINED; 9760Sstevel@tonic-gate return (0); 9770Sstevel@tonic-gate } 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate valuep->t = lval.t; 9800Sstevel@tonic-gate valuep->v = lval.v / rval.v; 9810Sstevel@tonic-gate return (1); 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate case T_MOD: 9840Sstevel@tonic-gate if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 9850Sstevel@tonic-gate arrowp, try, &lval)) 9860Sstevel@tonic-gate return (0); 9870Sstevel@tonic-gate if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 9880Sstevel@tonic-gate arrowp, try, &rval)) 9890Sstevel@tonic-gate return (0); 9900Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 9910Sstevel@tonic-gate return (0); 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate /* return false if dividing by zero */ 9940Sstevel@tonic-gate if (rval.v == 0) { 9950Sstevel@tonic-gate out(O_ERR, "eval_expr: T_MOD division by zero"); 9960Sstevel@tonic-gate valuep->t = UNDEFINED; 9970Sstevel@tonic-gate return (0); 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate valuep->t = lval.t; 10010Sstevel@tonic-gate valuep->v = lval.v % rval.v; 10020Sstevel@tonic-gate return (1); 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate case T_NAME: 10050Sstevel@tonic-gate if (try) { 10060Sstevel@tonic-gate struct iterinfo *iterinfop; 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate /* 10090Sstevel@tonic-gate * at itree_create() time, we can expand simple 10100Sstevel@tonic-gate * iterators. anything else we'll punt on. 10110Sstevel@tonic-gate */ 10120Sstevel@tonic-gate iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL); 10130Sstevel@tonic-gate if (iterinfop != NULL) { 10140Sstevel@tonic-gate /* explicit iterator; not part of pathname */ 10150Sstevel@tonic-gate valuep->t = UINT64; 10160Sstevel@tonic-gate valuep->v = (unsigned long long)iterinfop->num; 10170Sstevel@tonic-gate return (1); 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate return (0); 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate /* return address of struct node */ 10230Sstevel@tonic-gate valuep->t = NODEPTR; 10240Sstevel@tonic-gate valuep->v = (unsigned long long)np; 10250Sstevel@tonic-gate return (1); 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate case T_QUOTE: 10280Sstevel@tonic-gate valuep->t = STRING; 10290Sstevel@tonic-gate valuep->v = (unsigned long long)np->u.quote.s; 10300Sstevel@tonic-gate return (1); 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate case T_FUNC: 10330Sstevel@tonic-gate return (eval_func(np, ex, epnames, np->u.func.arglist, 10340Sstevel@tonic-gate globals, croot, arrowp, try, valuep)); 10350Sstevel@tonic-gate 10360Sstevel@tonic-gate case T_NUM: 10370Sstevel@tonic-gate valuep->t = UINT64; 10380Sstevel@tonic-gate valuep->v = np->u.ull; 10390Sstevel@tonic-gate return (1); 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate default: 10420Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 10430Sstevel@tonic-gate "eval_expr: unexpected node type: %s", 10440Sstevel@tonic-gate ptree_nodetype2str(np->t)); 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate /*NOTREACHED*/ 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate /* 10500Sstevel@tonic-gate * eval_fru() and eval_asru() don't do much, but are called from a number 10510Sstevel@tonic-gate * of places. 10520Sstevel@tonic-gate */ 10530Sstevel@tonic-gate struct node * 10540Sstevel@tonic-gate eval_fru(struct node *np) 10550Sstevel@tonic-gate { 10560Sstevel@tonic-gate ASSERT(np->t == T_NAME); 10570Sstevel@tonic-gate return (np); 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate struct node * 10610Sstevel@tonic-gate eval_asru(struct node *np) 10620Sstevel@tonic-gate { 10630Sstevel@tonic-gate ASSERT(np->t == T_NAME); 10640Sstevel@tonic-gate return (np); 10650Sstevel@tonic-gate } 1066