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