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 struct istat_entry ent; 361 362 ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t)); 363 364 ent.ename = np->u.event.ename->u.name.s; 365 ent.ipath = ipath(np->u.event.epname); 366 367 valuep->t = UINT64; 368 if ((statp = (struct stats *) 369 lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL) 370 valuep->v = 0; 371 else 372 valuep->v = stats_counter_value(statp); 373 374 return (1); 375 } else 376 outfl(O_DIE, np->file, np->line, 377 "eval_func: unexpected func: %s", funcname); 378 /*NOTREACHED*/ 379 } 380 381 static struct node * 382 eval_wildcardedname(struct node *np, struct lut *ex, struct node *epnames[]) 383 { 384 struct node *npstart, *npend, *npref, *newnp; 385 struct node *np1, *np2, *retp; 386 int i; 387 388 if (epnames == NULL || epnames[0] == NULL) 389 return (NULL); 390 391 for (i = 0; epnames[i] != NULL; i++) { 392 if (tree_namecmp(np, epnames[i]) == 0) 393 return (NULL); 394 } 395 396 /* 397 * get to this point if np does not match any of the entries in 398 * epnames. check if np is a path that must preceded by a wildcard 399 * portion. for this case we must first determine which epnames[] 400 * entry should be used for wildcarding. 401 */ 402 npstart = NULL; 403 for (i = 0; epnames[i] != NULL; i++) { 404 for (npref = epnames[i]; npref; npref = npref->u.name.next) { 405 if (npref->u.name.s == np->u.name.s) { 406 for (np1 = npref, np2 = np; 407 np1 != NULL && np2 != NULL; 408 np1 = np1->u.name.next, 409 np2 = np2->u.name.next) { 410 if (np1->u.name.s != np2->u.name.s) 411 break; 412 } 413 if (np2 == NULL) { 414 npstart = epnames[i]; 415 npend = npref; 416 if (np1 == NULL) 417 break; 418 } 419 } 420 } 421 422 if (npstart != NULL) 423 break; 424 } 425 426 if (npstart == NULL) { 427 /* no match; np is not a path to be wildcarded */ 428 return (NULL); 429 } 430 431 /* 432 * dup (npstart -- npend) which is the wildcarded portion. all 433 * children should be T_NUMs. 434 */ 435 retp = NULL; 436 for (npref = npstart; 437 ! (npref == NULL || npref == npend); 438 npref = npref->u.name.next) { 439 newnp = newnode(T_NAME, np->file, np->line); 440 441 newnp->u.name.t = npref->u.name.t; 442 newnp->u.name.s = npref->u.name.s; 443 newnp->u.name.last = newnp; 444 newnp->u.name.it = npref->u.name.it; 445 newnp->u.name.cp = npref->u.name.cp; 446 447 ASSERT(npref->u.name.child != NULL); 448 ASSERT(npref->u.name.child->t == T_NUM); 449 newnp->u.name.child = newnode(T_NUM, np->file, np->line); 450 newnp->u.name.child->u.ull = npref->u.name.child->u.ull; 451 452 if (retp == NULL) { 453 retp = newnp; 454 } else { 455 retp->u.name.last->u.name.next = newnp; 456 retp->u.name.last = newnp; 457 } 458 } 459 460 ASSERT(retp != NULL); 461 462 /* now append the nonwildcarded portion */ 463 retp = tree_name_append(retp, eval_dup(np, ex, NULL)); 464 465 return (retp); 466 } 467 468 static struct node * 469 eval_dup(struct node *np, struct lut *ex, struct node *epnames[]) 470 { 471 struct node *newnp; 472 473 if (np == NULL) 474 return (NULL); 475 476 switch (np->t) { 477 case T_GLOBID: 478 return (tree_globid(np->u.globid.s, np->file, np->line)); 479 480 case T_ASSIGN: 481 case T_CONDIF: 482 case T_CONDELSE: 483 case T_NE: 484 case T_EQ: 485 case T_LT: 486 case T_LE: 487 case T_GT: 488 case T_GE: 489 case T_BITAND: 490 case T_BITOR: 491 case T_BITXOR: 492 case T_BITNOT: 493 case T_LSHIFT: 494 case T_RSHIFT: 495 case T_LIST: 496 case T_AND: 497 case T_OR: 498 case T_NOT: 499 case T_ADD: 500 case T_SUB: 501 case T_MUL: 502 case T_DIV: 503 case T_MOD: 504 return (tree_expr(np->t, 505 eval_dup(np->u.expr.left, ex, epnames), 506 eval_dup(np->u.expr.right, ex, epnames))); 507 508 case T_NAME: { 509 struct iterinfo *iterinfop; 510 struct node *newchild = NULL; 511 512 iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL); 513 if (iterinfop != NULL) { 514 /* explicit iterator; not part of pathname */ 515 newnp = newnode(T_NUM, np->file, np->line); 516 newnp->u.ull = iterinfop->num; 517 return (newnp); 518 } 519 520 /* see if np is a path with wildcard portion */ 521 newnp = eval_wildcardedname(np, ex, epnames); 522 if (newnp != NULL) 523 return (newnp); 524 525 /* turn off wildcarding for child */ 526 newchild = eval_dup(np->u.name.child, ex, NULL); 527 528 if (newchild != NULL) { 529 if (newchild->t != T_NUM) { 530 /* 531 * not a number, eh? we must resolve this 532 * to a number. 533 */ 534 struct evalue value; 535 536 if (eval_expr(newchild, ex, epnames, 537 NULL, NULL, NULL, 1, &value) == 0 || 538 value.t != UINT64) { 539 outfl(O_DIE, np->file, np->line, 540 "eval_dup: could not resolve " 541 "iterator of %s", np->u.name.s); 542 } 543 544 tree_free(newchild); 545 newchild = newnode(T_NUM, np->file, np->line); 546 newchild->u.ull = value.v; 547 } 548 549 newnp = newnode(np->t, np->file, np->line); 550 newnp->u.name.s = np->u.name.s; 551 newnp->u.name.it = np->u.name.it; 552 newnp->u.name.cp = np->u.name.cp; 553 554 newnp->u.name.last = newnp; 555 newnp->u.name.child = newchild; 556 557 if (np->u.name.next != NULL) { 558 /* turn off wildcarding for next */ 559 return (tree_name_append(newnp, 560 eval_dup(np->u.name.next, ex, NULL))); 561 } else { 562 return (newnp); 563 } 564 } else { 565 outfl(O_DIE, np->file, np->line, 566 "eval_dup: internal error: \"%s\" is neither " 567 "an iterator nor a pathname", np->u.name.s); 568 } 569 /*NOTREACHED*/ 570 break; 571 } 572 573 case T_EVENT: 574 newnp = newnode(T_NAME, np->file, np->line); 575 576 newnp->u.name.t = np->u.event.ename->u.name.t; 577 newnp->u.name.s = np->u.event.ename->u.name.s; 578 newnp->u.name.it = np->u.event.ename->u.name.it; 579 newnp->u.name.last = newnp; 580 581 return (tree_event(newnp, 582 eval_dup(np->u.event.epname, ex, epnames), 583 eval_dup(np->u.event.eexprlist, ex, epnames))); 584 585 case T_FUNC: 586 return (tree_func(np->u.func.s, 587 eval_dup(np->u.func.arglist, ex, epnames), 588 np->file, np->line)); 589 590 case T_QUOTE: 591 newnp = newnode(T_QUOTE, np->file, np->line); 592 newnp->u.quote.s = np->u.quote.s; 593 return (newnp); 594 595 case T_NUM: 596 newnp = newnode(T_NUM, np->file, np->line); 597 newnp->u.ull = np->u.ull; 598 return (newnp); 599 600 default: 601 outfl(O_DIE, np->file, np->line, 602 "eval_dup: unexpected node type: %s", 603 ptree_nodetype2str(np->t)); 604 } 605 /*NOTREACHED*/ 606 } 607 608 /* 609 * eval_potential -- see if constraint is potentially true 610 * 611 * this function is used at instance tree creation time to see if 612 * any constraints are already known to be false. if this function 613 * returns false, then the constraint will always be false and there's 614 * no need to include the propagation arrow in the instance tree. 615 * 616 * if this routine returns true, either the constraint is known to 617 * be always true (so there's no point in attaching the constraint 618 * to the propagation arrow in the instance tree), or the constraint 619 * contains "deferred" expressions like global variables or poller calls 620 * and so it must be evaluated during calls to fme_eval(). in this last 621 * case, where a constraint needs to be attached to the propagation arrow 622 * in the instance tree, this routine returns a newly created constraint 623 * in *newc where all the non-deferred things have been filled in. 624 * 625 * so in summary: 626 * 627 * return of false: constraint can never be true, *newc will be NULL. 628 * 629 * return of true with *newc unchanged: constraint will always be true. 630 * 631 * return of true with *newc changed: use new constraint in *newc. 632 * 633 * the lookup table for all explicit iterators, ex, is passed in. 634 * 635 * *newc can either be NULL on entry, or if can contain constraints from 636 * previous calls to eval_potential() (i.e. for building up an instance 637 * tree constraint from several potential constraints). if *newc already 638 * contains constraints, anything added to it will be joined by adding 639 * a T_AND node at the top of *newc. 640 */ 641 int 642 eval_potential(struct node *np, struct lut *ex, struct node *epnames[], 643 struct node **newc) 644 { 645 struct node *newnp; 646 struct evalue value; 647 648 if (eval_expr(np, ex, epnames, NULL, NULL, NULL, 1, &value) == 0) { 649 /* 650 * couldn't eval expression because 651 * it contains deferred items. make 652 * a duplicate expression with all the 653 * non-deferred items expanded. 654 */ 655 newnp = eval_dup(np, ex, epnames); 656 657 if (*newc == NULL) { 658 /* 659 * constraint is potentially true if deferred 660 * expression in newnp is true. *newc was NULL 661 * so new constraint is just the one in newnp. 662 */ 663 *newc = newnp; 664 return (1); 665 } else { 666 /* 667 * constraint is potentially true if deferred 668 * expression in newnp is true. *newc already 669 * contained a constraint so add an AND with the 670 * constraint in newnp. 671 */ 672 *newc = tree_expr(T_AND, *newc, newnp); 673 return (1); 674 } 675 } else if (value.t == UNDEFINED) { 676 /* constraint can never be true */ 677 return (0); 678 } else if (value.t == UINT64 && value.v == 0) { 679 /* constraint can never be true */ 680 return (0); 681 } else { 682 /* constraint is always true (nothing deferred to eval) */ 683 return (1); 684 } 685 } 686 687 static int 688 check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype, 689 struct node *np) 690 { 691 /* auto-convert T_NAMES to strings */ 692 if (lp->t == NODEPTR && ((struct node *)(lp->v))->t == T_NAME) { 693 char *s = ipath2str(NULL, ipath((struct node *)lp->v)); 694 lp->t = STRING; 695 lp->v = (unsigned long long)stable(s); 696 FREE(s); 697 out(O_ALTFP|O_VERB2, "convert lhs path to \"%s\"", 698 (char *)lp->v); 699 } 700 if (rp != NULL && 701 rp->t == NODEPTR && ((struct node *)(rp->v))->t == T_NAME) { 702 char *s = ipath2str(NULL, ipath((struct node *)rp->v)); 703 rp->t = STRING; 704 rp->v = (unsigned long long)stable(s); 705 FREE(s); 706 out(O_ALTFP|O_VERB2, "convert rhs path to \"%s\"", 707 (char *)rp->v); 708 } 709 710 /* auto-convert strings to numbers */ 711 if (dtype == UINT64) { 712 if (lp->t == STRING) { 713 lp->t = UINT64; 714 lp->v = strtoull((char *)lp->v, NULL, 0); 715 } 716 if (rp != NULL && rp->t == STRING) { 717 rp->t = UINT64; 718 rp->v = strtoull((char *)rp->v, NULL, 0); 719 } 720 } 721 722 if (dtype != UNDEFINED && lp->t != dtype) { 723 outfl(O_OK, np->file, np->line, 724 "invalid datatype of argument for operation %s", 725 ptree_nodetype2str(np->t)); 726 return (1); 727 } 728 729 if (rp != NULL && lp->t != rp->t) { 730 outfl(O_OK, np->file, np->line, 731 "mismatch in datatype of arguments for operation %s", 732 ptree_nodetype2str(np->t)); 733 return (1); 734 } 735 736 return (0); 737 } 738 739 /* 740 * eval_expr -- evaluate expression into *valuep 741 * 742 * the meaning of the return value depends on the input value of try. 743 * 744 * for try == 1: if any deferred items are encounted, bail out and return 745 * false. returns true if we made it through entire expression without 746 * hitting any deferred items. 747 * 748 * for try == 0: return true if all operations were performed successfully. 749 * return false if otherwise. for example, any of the following conditions 750 * will result in a false return value: 751 * - attempted use of an uninitialized global variable 752 * - failure in function evaluation 753 * - illegal arithmetic operation (argument out of range) 754 */ 755 int 756 eval_expr(struct node *np, struct lut *ex, struct node *epnames[], 757 struct lut **globals, struct config *croot, struct arrow *arrowp, 758 int try, struct evalue *valuep) 759 { 760 struct evalue *gval; 761 struct evalue lval; 762 struct evalue rval; 763 764 if (np == NULL) { 765 valuep->t = UINT64; 766 valuep->v = 1; /* no constraint means "true" */ 767 return (1); 768 } 769 770 valuep->t = UNDEFINED; 771 772 switch (np->t) { 773 case T_GLOBID: 774 if (try) 775 return (0); 776 777 /* 778 * only handle case of getting (and not setting) the value 779 * of a global variable 780 */ 781 gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL); 782 if (gval == NULL) { 783 valuep->t = UNDEFINED; 784 return (0); 785 } else { 786 valuep->t = gval->t; 787 valuep->v = gval->v; 788 return (1); 789 } 790 791 case T_ASSIGN: 792 if (try) 793 return (0); 794 795 /* 796 * first evaluate rhs, then try to store value in lhs which 797 * should be a global variable 798 */ 799 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 800 arrowp, try, &rval)) 801 return (0); 802 803 ASSERT(np->u.expr.left->t == T_GLOBID); 804 gval = lut_lookup(*globals, 805 (void *)np->u.expr.left->u.globid.s, NULL); 806 807 if (gval == NULL) { 808 gval = MALLOC(sizeof (*gval)); 809 *globals = lut_add(*globals, 810 (void *) np->u.expr.left->u.globid.s, 811 gval, NULL); 812 } 813 814 gval->t = rval.t; 815 gval->v = rval.v; 816 817 if (gval->t == UINT64) { 818 out(O_ALTFP|O_VERB2, 819 "assign $%s=%llu", 820 np->u.expr.left->u.globid.s, gval->v); 821 } else { 822 out(O_ALTFP|O_VERB2, 823 "assign $%s=\"%s\"", 824 np->u.expr.left->u.globid.s, (char *)gval->v); 825 } 826 827 /* 828 * but always return true -- an assignment should not 829 * cause a constraint to be false. 830 */ 831 valuep->t = UINT64; 832 valuep->v = 1; 833 return (1); 834 835 case T_EQ: 836 #define IMPLICIT_ASSIGN_IN_EQ 837 #ifdef IMPLICIT_ASSIGN_IN_EQ 838 /* 839 * if lhs is an uninitialized global variable, perform 840 * an assignment. 841 * 842 * one insidious side effect of implicit assignment is 843 * that the "==" operator does not return a Boolean if 844 * implicit assignment was performed. 845 */ 846 if (try == 0 && 847 np->u.expr.left->t == T_GLOBID && 848 (gval = lut_lookup(*globals, 849 (void *)np->u.expr.left->u.globid.s, NULL)) == NULL) { 850 if (!eval_expr(np->u.expr.right, ex, epnames, globals, 851 croot, arrowp, try, &rval)) 852 return (0); 853 854 gval = MALLOC(sizeof (*gval)); 855 *globals = lut_add(*globals, 856 (void *) np->u.expr.left->u.globid.s, 857 gval, NULL); 858 859 gval->t = rval.t; 860 gval->v = rval.v; 861 valuep->t = rval.t; 862 valuep->v = rval.v; 863 return (1); 864 } 865 #endif /* IMPLICIT_ASSIGN_IN_EQ */ 866 867 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 868 arrowp, try, &lval)) 869 return (0); 870 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 871 arrowp, try, &rval)) 872 return (0); 873 if (check_expr_args(&lval, &rval, UNDEFINED, np)) 874 return (0); 875 876 valuep->t = UINT64; 877 valuep->v = (lval.v == rval.v); 878 return (1); 879 880 case T_LT: 881 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 882 arrowp, try, &lval)) 883 return (0); 884 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 885 arrowp, try, &rval)) 886 return (0); 887 if (check_expr_args(&lval, &rval, UINT64, np)) 888 return (0); 889 890 valuep->t = UINT64; 891 valuep->v = (lval.v < rval.v); 892 return (1); 893 894 case T_LE: 895 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 896 arrowp, try, &lval)) 897 return (0); 898 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 899 arrowp, try, &rval)) 900 return (0); 901 if (check_expr_args(&lval, &rval, UINT64, np)) 902 return (0); 903 904 valuep->t = UINT64; 905 valuep->v = (lval.v <= rval.v); 906 return (1); 907 908 case T_GT: 909 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 910 arrowp, try, &lval)) 911 return (0); 912 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 913 arrowp, try, &rval)) 914 return (0); 915 if (check_expr_args(&lval, &rval, UINT64, np)) 916 return (0); 917 918 valuep->t = UINT64; 919 valuep->v = (lval.v > rval.v); 920 return (1); 921 922 case T_GE: 923 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 924 arrowp, try, &lval)) 925 return (0); 926 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 927 arrowp, try, &rval)) 928 return (0); 929 if (check_expr_args(&lval, &rval, UINT64, np)) 930 return (0); 931 932 valuep->t = UINT64; 933 valuep->v = (lval.v >= rval.v); 934 return (1); 935 936 case T_BITAND: 937 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 938 arrowp, try, &lval)) 939 return (0); 940 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 941 arrowp, try, &rval)) 942 return (0); 943 if (check_expr_args(&lval, &rval, UINT64, np)) 944 return (0); 945 946 valuep->t = lval.t; 947 valuep->v = (lval.v & rval.v); 948 return (1); 949 950 case T_BITOR: 951 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 952 arrowp, try, &lval)) 953 return (0); 954 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 955 arrowp, try, &rval)) 956 return (0); 957 if (check_expr_args(&lval, &rval, UINT64, np)) 958 return (0); 959 960 valuep->t = lval.t; 961 valuep->v = (lval.v | rval.v); 962 return (1); 963 964 case T_BITXOR: 965 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 966 arrowp, try, &lval)) 967 return (0); 968 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 969 arrowp, try, &rval)) 970 return (0); 971 if (check_expr_args(&lval, &rval, UINT64, np)) 972 return (0); 973 974 valuep->t = lval.t; 975 valuep->v = (lval.v ^ rval.v); 976 return (1); 977 978 case T_BITNOT: 979 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 980 arrowp, try, &lval)) 981 return (0); 982 ASSERT(np->u.expr.right == NULL); 983 if (check_expr_args(&lval, NULL, UINT64, np)) 984 return (0); 985 986 valuep->t = UINT64; 987 valuep->v = ~ lval.v; 988 return (1); 989 990 case T_LSHIFT: 991 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 992 arrowp, try, &lval)) 993 return (0); 994 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 995 arrowp, try, &rval)) 996 return (0); 997 if (check_expr_args(&lval, &rval, UINT64, np)) 998 return (0); 999 1000 valuep->t = UINT64; 1001 valuep->v = (lval.v << rval.v); 1002 return (1); 1003 1004 case T_RSHIFT: 1005 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 1006 arrowp, try, &lval)) 1007 return (0); 1008 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 1009 arrowp, try, &rval)) 1010 return (0); 1011 if (check_expr_args(&lval, &rval, UINT64, np)) 1012 return (0); 1013 1014 valuep->t = UINT64; 1015 valuep->v = (lval.v >> rval.v); 1016 return (1); 1017 1018 case T_CONDIF: { 1019 struct node *retnp; 1020 int dotrue = 0; 1021 1022 /* 1023 * evaluate 1024 * expression ? stmtA [ : stmtB ] 1025 * 1026 * first see if expression is true or false, then determine 1027 * if stmtA (or stmtB, if it exists) should be evaluated. 1028 * 1029 * "dotrue = 1" means stmtA should be evaluated. 1030 */ 1031 if (eval_expr(np->u.expr.left, ex, epnames, globals, croot, 1032 arrowp, try, &lval) && 1033 lval.t != UNDEFINED && lval.v != 0) 1034 dotrue = 1; 1035 1036 ASSERT(np->u.expr.right != NULL); 1037 if (np->u.expr.right->t == T_CONDELSE) { 1038 if (dotrue) 1039 retnp = np->u.expr.right->u.expr.left; 1040 else 1041 retnp = np->u.expr.right->u.expr.right; 1042 } else { 1043 /* no ELSE clause */ 1044 if (dotrue) 1045 retnp = np->u.expr.right; 1046 else { 1047 valuep->t = UINT64; 1048 valuep->v = 0; 1049 return (0); 1050 } 1051 } 1052 1053 if (!eval_expr(retnp, ex, epnames, globals, croot, 1054 arrowp, try, valuep)) 1055 return (0); 1056 return (1); 1057 } 1058 1059 case T_CONDELSE: 1060 /* 1061 * shouldn't get here, since T_CONDELSE is supposed to be 1062 * evaluated as part of T_CONDIF 1063 */ 1064 out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s", 1065 ptree_nodetype2str(np->t)); 1066 return (0); 1067 1068 case T_NE: 1069 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 1070 arrowp, try, &lval)) 1071 return (0); 1072 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 1073 arrowp, try, &rval)) 1074 return (0); 1075 if (check_expr_args(&lval, &rval, UNDEFINED, np)) 1076 return (0); 1077 1078 valuep->t = UINT64; 1079 valuep->v = (lval.v != rval.v); 1080 return (1); 1081 1082 case T_LIST: 1083 case T_AND: 1084 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 1085 arrowp, try, valuep)) 1086 return (0); 1087 if (valuep->v == 0) { 1088 valuep->t = UINT64; 1089 return (1); 1090 } 1091 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 1092 arrowp, try, valuep)) 1093 return (0); 1094 valuep->t = UINT64; 1095 valuep->v = valuep->v == 0 ? 0 : 1; 1096 return (1); 1097 1098 case T_OR: 1099 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 1100 arrowp, try, valuep)) 1101 return (0); 1102 if (valuep->v != 0) { 1103 valuep->t = UINT64; 1104 valuep->v = 1; 1105 return (1); 1106 } 1107 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 1108 arrowp, try, valuep)) 1109 return (0); 1110 valuep->t = UINT64; 1111 valuep->v = valuep->v == 0 ? 0 : 1; 1112 return (1); 1113 1114 case T_NOT: 1115 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 1116 arrowp, try, valuep)) 1117 return (0); 1118 valuep->t = UINT64; 1119 valuep->v = ! valuep->v; 1120 return (1); 1121 1122 case T_ADD: 1123 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 1124 arrowp, try, &lval)) 1125 return (0); 1126 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 1127 arrowp, try, &rval)) 1128 return (0); 1129 if (check_expr_args(&lval, &rval, UINT64, np)) 1130 return (0); 1131 1132 valuep->t = lval.t; 1133 valuep->v = lval.v + rval.v; 1134 return (1); 1135 1136 case T_SUB: 1137 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 1138 arrowp, try, &lval)) 1139 return (0); 1140 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 1141 arrowp, try, &rval)) 1142 return (0); 1143 if (check_expr_args(&lval, &rval, UINT64, np)) 1144 return (0); 1145 1146 /* since valuep is unsigned, return false if lval.v < rval.v */ 1147 if (lval.v < rval.v) { 1148 out(O_ERR, "eval_expr: T_SUB result is out of range"); 1149 valuep->t = UNDEFINED; 1150 return (0); 1151 } 1152 1153 valuep->t = lval.t; 1154 valuep->v = lval.v - rval.v; 1155 return (1); 1156 1157 case T_MUL: 1158 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 1159 arrowp, try, &lval)) 1160 return (0); 1161 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 1162 arrowp, try, &rval)) 1163 return (0); 1164 if (check_expr_args(&lval, &rval, UINT64, np)) 1165 return (0); 1166 1167 valuep->t = lval.t; 1168 valuep->v = lval.v * rval.v; 1169 return (1); 1170 1171 case T_DIV: 1172 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 1173 arrowp, try, &lval)) 1174 return (0); 1175 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 1176 arrowp, try, &rval)) 1177 return (0); 1178 if (check_expr_args(&lval, &rval, UINT64, np)) 1179 return (0); 1180 1181 /* return false if dividing by zero */ 1182 if (rval.v == 0) { 1183 out(O_ERR, "eval_expr: T_DIV division by zero"); 1184 valuep->t = UNDEFINED; 1185 return (0); 1186 } 1187 1188 valuep->t = lval.t; 1189 valuep->v = lval.v / rval.v; 1190 return (1); 1191 1192 case T_MOD: 1193 if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot, 1194 arrowp, try, &lval)) 1195 return (0); 1196 if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, 1197 arrowp, try, &rval)) 1198 return (0); 1199 if (check_expr_args(&lval, &rval, UINT64, np)) 1200 return (0); 1201 1202 /* return false if dividing by zero */ 1203 if (rval.v == 0) { 1204 out(O_ERR, "eval_expr: T_MOD division by zero"); 1205 valuep->t = UNDEFINED; 1206 return (0); 1207 } 1208 1209 valuep->t = lval.t; 1210 valuep->v = lval.v % rval.v; 1211 return (1); 1212 1213 case T_NAME: 1214 if (try) { 1215 struct iterinfo *iterinfop; 1216 1217 /* 1218 * at itree_create() time, we can expand simple 1219 * iterators. anything else we'll punt on. 1220 */ 1221 iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL); 1222 if (iterinfop != NULL) { 1223 /* explicit iterator; not part of pathname */ 1224 valuep->t = UINT64; 1225 valuep->v = (unsigned long long)iterinfop->num; 1226 return (1); 1227 } 1228 return (0); 1229 } 1230 1231 /* return address of struct node */ 1232 valuep->t = NODEPTR; 1233 valuep->v = (unsigned long long)np; 1234 return (1); 1235 1236 case T_QUOTE: 1237 valuep->t = STRING; 1238 valuep->v = (unsigned long long)np->u.quote.s; 1239 return (1); 1240 1241 case T_FUNC: 1242 return (eval_func(np, ex, epnames, np->u.func.arglist, 1243 globals, croot, arrowp, try, valuep)); 1244 1245 case T_NUM: 1246 valuep->t = UINT64; 1247 valuep->v = np->u.ull; 1248 return (1); 1249 1250 default: 1251 outfl(O_DIE, np->file, np->line, 1252 "eval_expr: unexpected node type: %s", 1253 ptree_nodetype2str(np->t)); 1254 } 1255 /*NOTREACHED*/ 1256 } 1257 1258 /* 1259 * eval_fru() and eval_asru() don't do much, but are called from a number 1260 * of places. 1261 */ 1262 struct node * 1263 eval_fru(struct node *np) 1264 { 1265 ASSERT(np->t == T_NAME); 1266 return (np); 1267 } 1268 1269 struct node * 1270 eval_asru(struct node *np) 1271 { 1272 ASSERT(np->t == T_NAME); 1273 return (np); 1274 } 1275