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