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