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