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 2010 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 #include <stdio.h> 32 #include <stdlib.h> 33 #include <ctype.h> 34 #include <string.h> 35 #include <fm/libtopo.h> 36 #include "alloc.h" 37 #include "out.h" 38 #include "stable.h" 39 #include "literals.h" 40 #include "lut.h" 41 #include "tree.h" 42 #include "ptree.h" 43 #include "itree.h" 44 #include "ipath.h" 45 #include "eval.h" 46 #include "config.h" 47 #include "platform.h" 48 #include "fme.h" 49 #include "stats.h" 50 51 static struct node *eval_dup(struct node *np, struct lut *ex, 52 struct node *events[]); 53 static int check_expr_args(struct evalue *lp, struct evalue *rp, 54 enum datatype dtype, struct node *np); 55 static struct node *eval_fru(struct node *np); 56 static struct node *eval_asru(struct node *np); 57 58 extern fmd_hdl_t *Hdl; /* handle from eft.c */ 59 60 /* 61 * begins_with -- return true if rhs path begins with everything in lhs path 62 */ 63 static int 64 begins_with(struct node *lhs, struct node *rhs, struct lut *ex) 65 { 66 int lnum; 67 int rnum; 68 struct iterinfo *iterinfop; 69 70 if (lhs == NULL) 71 return (1); /* yep -- it all matched */ 72 73 if (rhs == NULL) 74 return (0); /* nope, ran out of rhs first */ 75 76 ASSERTeq(lhs->t, T_NAME, ptree_nodetype2str); 77 ASSERTeq(rhs->t, T_NAME, ptree_nodetype2str); 78 79 if (lhs->u.name.s != rhs->u.name.s) 80 return (0); /* nope, different component names */ 81 82 if (lhs->u.name.child && lhs->u.name.child->t == T_NUM) { 83 lnum = (int)lhs->u.name.child->u.ull; 84 } else if (lhs->u.name.child && lhs->u.name.child->t == T_NAME) { 85 iterinfop = lut_lookup(ex, (void *)lhs->u.name.child->u.name.s, 86 NULL); 87 if (iterinfop != NULL) 88 lnum = iterinfop->num; 89 else 90 out(O_DIE, "begins_with: unexpected lhs child"); 91 } else { 92 out(O_DIE, "begins_with: unexpected lhs child"); 93 } 94 95 if (rhs->u.name.child && rhs->u.name.child->t == T_NUM) { 96 rnum = (int)rhs->u.name.child->u.ull; 97 } else if (rhs->u.name.child && rhs->u.name.child->t == T_NAME) { 98 iterinfop = lut_lookup(ex, (void *)rhs->u.name.child->u.name.s, 99 NULL); 100 if (iterinfop != NULL) 101 rnum = iterinfop->num; 102 else 103 out(O_DIE, "begins_with: unexpected rhs child"); 104 } else { 105 out(O_DIE, "begins_with: unexpected rhs child"); 106 } 107 108 if (lnum != rnum) 109 return (0); /* nope, instance numbers were different */ 110 111 return (begins_with(lhs->u.name.next, rhs->u.name.next, ex)); 112 } 113 114 /* 115 * eval_getname - used by eval_func to evaluate a name, preferably without using 116 * eval_dup (but if it does have to use eval_dup then the *dupedp flag is set). 117 */ 118 static struct node * 119 eval_getname(struct node *funcnp, struct lut *ex, struct node *events[], 120 struct node *np, struct lut **globals, 121 struct config *croot, struct arrow *arrowp, int try, int *dupedp) 122 { 123 struct node *nodep; 124 const char *funcname = funcnp->u.func.s; 125 struct evalue val; 126 127 if (np->t == T_NAME) 128 nodep = np; 129 else if (np->t == T_FUNC && np->u.func.s == L_fru) 130 nodep = eval_fru(np->u.func.arglist); 131 else if (np->t == T_FUNC && np->u.func.s == L_asru) 132 nodep = eval_asru(np->u.func.arglist); 133 else if (np->t == T_FUNC) { 134 if (eval_expr(np, ex, events, globals, croot, arrowp, try, 135 &val) == 0) 136 /* 137 * Can't evaluate yet. Return null so constraint is 138 * deferred. 139 */ 140 return (NULL); 141 if (val.t == NODEPTR) 142 return ((struct node *)(uintptr_t)val.v); 143 else 144 /* 145 * just return the T_FUNC - which the caller will 146 * reject. 147 */ 148 return (np); 149 } else 150 out(O_DIE, "%s: unexpected type: %s", 151 funcname, ptree_nodetype2str(np->t)); 152 if (try) { 153 if (eval_expr(nodep, ex, events, globals, croot, 154 arrowp, try, &val) && val.t == NODEPTR) 155 nodep = (struct node *)(uintptr_t)val.v; 156 else { 157 *dupedp = 1; 158 nodep = eval_dup(nodep, ex, events); 159 } 160 } 161 return (nodep); 162 } 163 164 /*ARGSUSED*/ 165 static int 166 eval_cat(struct node *np, struct lut *ex, struct node *events[], 167 struct lut **globals, struct config *croot, struct arrow *arrowp, 168 int try, struct evalue *valuep) 169 { 170 if (np->t == T_LIST) { 171 struct evalue lval; 172 struct evalue rval; 173 int len; 174 char *s; 175 176 if (!eval_cat(np->u.expr.left, ex, events, globals, croot, 177 arrowp, try, &lval)) 178 return (0); 179 if (!eval_cat(np->u.expr.right, ex, events, globals, croot, 180 arrowp, try, &rval)) 181 return (0); 182 len = snprintf(NULL, 0, "%s%s", (char *)(uintptr_t)lval.v, 183 (char *)(uintptr_t)rval.v); 184 s = MALLOC(len + 1); 185 186 (void) snprintf(s, len + 1, "%s%s", (char *)(uintptr_t)lval.v, 187 (char *)(uintptr_t)rval.v); 188 outfl(O_ALTFP|O_VERB2, np->file, np->line, 189 "eval_cat: %s %s returns %s", (char *)(uintptr_t)lval.v, 190 (char *)(uintptr_t)rval.v, s); 191 valuep->t = STRING; 192 valuep->v = (uintptr_t)stable(s); 193 FREE(s); 194 } else { 195 if (!eval_expr(np, ex, events, globals, croot, 196 arrowp, try, valuep)) 197 return (0); 198 if (check_expr_args(valuep, NULL, STRING, np)) 199 return (0); 200 } 201 return (1); 202 } 203 204 /* 205 * evaluate a variety of functions and place result in valuep. return 1 if 206 * function evaluation was successful; 0 if otherwise (e.g., the case of an 207 * invalid argument to the function) 208 */ 209 /*ARGSUSED*/ 210 static int 211 eval_func(struct node *funcnp, struct lut *ex, struct node *events[], 212 struct node *np, struct lut **globals, 213 struct config *croot, struct arrow *arrowp, int try, struct evalue *valuep) 214 { 215 const char *funcname = funcnp->u.func.s; 216 int duped_lhs = 0, duped_rhs = 0, duped = 0; 217 struct node *lhs; 218 struct node *rhs; 219 struct config *cp; 220 struct node *nodep; 221 char *path; 222 struct evalue val; 223 224 if (funcname == L_within) { 225 /* within()'s are not really constraints -- always true */ 226 valuep->t = UINT64; 227 valuep->v = 1; 228 return (1); 229 } else if (funcname == L_is_under) { 230 lhs = eval_getname(funcnp, ex, events, np->u.expr.left, globals, 231 croot, arrowp, try, &duped_lhs); 232 rhs = eval_getname(funcnp, ex, events, np->u.expr.right, 233 globals, croot, arrowp, try, &duped_rhs); 234 if (!rhs || !lhs) 235 return (0); 236 if (rhs->t != T_NAME || lhs->t != T_NAME) { 237 valuep->t = UNDEFINED; 238 return (1); 239 } 240 241 valuep->t = UINT64; 242 valuep->v = begins_with(lhs, rhs, ex); 243 out(O_ALTFP|O_VERB2|O_NONL, "eval_func:is_under("); 244 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, lhs); 245 out(O_ALTFP|O_VERB2|O_NONL, ","); 246 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, rhs); 247 out(O_ALTFP|O_VERB2|O_NONL, ") returned %d", (int)valuep->v); 248 249 if (duped_lhs) 250 tree_free(lhs); 251 if (duped_rhs) 252 tree_free(rhs); 253 return (1); 254 } else if (funcname == L_confprop || funcname == L_confprop_defined) { 255 const char *s; 256 257 /* for now s will point to a quote [see addconfigprop()] */ 258 ASSERT(np->u.expr.right->t == T_QUOTE); 259 260 nodep = eval_getname(funcnp, ex, events, np->u.expr.left, 261 globals, croot, arrowp, try, &duped); 262 if (!nodep) 263 return (0); 264 if (nodep->t != T_NAME) { 265 valuep->t = UNDEFINED; 266 return (1); 267 } 268 269 if (nodep->u.name.last->u.name.cp != NULL) { 270 cp = nodep->u.name.last->u.name.cp; 271 } else { 272 path = ipath2str(NULL, ipath(nodep)); 273 cp = config_lookup(croot, path, 0); 274 FREE((void *)path); 275 } 276 if (cp == NULL) { 277 if (funcname == L_confprop) { 278 out(O_ALTFP|O_VERB3, "%s: path ", funcname); 279 ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep); 280 out(O_ALTFP|O_VERB3, " not found"); 281 valuep->v = (uintptr_t)stable(""); 282 valuep->t = STRING; 283 if (duped) 284 tree_free(nodep); 285 return (1); 286 } else { 287 valuep->v = 0; 288 valuep->t = UINT64; 289 if (duped) 290 tree_free(nodep); 291 return (1); 292 } 293 } 294 s = config_getprop(cp, np->u.expr.right->u.quote.s); 295 if (s == NULL && strcmp(np->u.expr.right->u.quote.s, 296 "class-code") == 0) 297 s = config_getprop(cp, "CLASS-CODE"); 298 if (s == NULL) { 299 if (funcname == L_confprop) { 300 out(O_ALTFP|O_VERB3|O_NONL, 301 "%s: \"%s\" not found for path ", 302 funcname, np->u.expr.right->u.quote.s); 303 ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep); 304 valuep->v = (uintptr_t)stable(""); 305 valuep->t = STRING; 306 if (duped) 307 tree_free(nodep); 308 return (1); 309 } else { 310 valuep->v = 0; 311 valuep->t = UINT64; 312 if (duped) 313 tree_free(nodep); 314 return (1); 315 } 316 } 317 318 if (funcname == L_confprop) { 319 valuep->v = (uintptr_t)stable(s); 320 valuep->t = STRING; 321 out(O_ALTFP|O_VERB3|O_NONL, " %s(\"", funcname); 322 ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep); 323 out(O_ALTFP|O_VERB3|O_NONL, 324 "\", \"%s\") = \"%s\" ", 325 np->u.expr.right->u.quote.s, 326 (char *)(uintptr_t)valuep->v); 327 } else { 328 valuep->v = 1; 329 valuep->t = UINT64; 330 } 331 if (duped) 332 tree_free(nodep); 333 return (1); 334 } else if (funcname == L_is_connected) { 335 const char *connstrings[] = { "connected", "CONNECTED", NULL }; 336 struct config *cp[2]; 337 const char *matchthis[2], *s; 338 char *nameslist, *w; 339 int i, j; 340 341 lhs = eval_getname(funcnp, ex, events, np->u.expr.left, globals, 342 croot, arrowp, try, &duped_lhs); 343 rhs = eval_getname(funcnp, ex, events, np->u.expr.right, 344 globals, croot, arrowp, try, &duped_rhs); 345 if (!rhs || !lhs) 346 return (0); 347 if (rhs->t != T_NAME || lhs->t != T_NAME) { 348 valuep->t = UNDEFINED; 349 return (1); 350 } 351 352 path = ipath2str(NULL, ipath(lhs)); 353 matchthis[1] = stable(path); 354 if (lhs->u.name.last->u.name.cp != NULL) 355 cp[0] = lhs->u.name.last->u.name.cp; 356 else 357 cp[0] = config_lookup(croot, path, 0); 358 FREE((void *)path); 359 path = ipath2str(NULL, ipath(rhs)); 360 matchthis[0] = stable(path); 361 if (rhs->u.name.last->u.name.cp != NULL) 362 cp[1] = rhs->u.name.last->u.name.cp; 363 else 364 cp[1] = config_lookup(croot, path, 0); 365 FREE((void *)path); 366 if (duped_lhs) 367 tree_free(lhs); 368 if (duped_rhs) 369 tree_free(rhs); 370 371 valuep->t = UINT64; 372 valuep->v = 0; 373 if (cp[0] == NULL || cp[1] == NULL) 374 return (1); 375 376 /* to thine self always be connected */ 377 if (cp[0] == cp[1]) { 378 valuep->v = 1; 379 return (1); 380 } 381 382 /* 383 * Extract "connected" property from each cp. Search this 384 * property for the name associated with the other cp[]. 385 */ 386 for (i = 0; i < 2 && valuep->v == 0; i++) { 387 for (j = 0; connstrings[j] != NULL && valuep->v == 0; 388 j++) { 389 s = config_getprop(cp[i], 390 stable(connstrings[j])); 391 if (s != NULL) { 392 nameslist = STRDUP(s); 393 w = strtok(nameslist, " ,"); 394 while (w != NULL) { 395 if (stable(w) == matchthis[i]) { 396 valuep->v = 1; 397 break; 398 } 399 w = strtok(NULL, " ,"); 400 } 401 FREE(nameslist); 402 } 403 } 404 } 405 return (1); 406 } else if (funcname == L_is_type) { 407 const char *typestrings[] = { "type", "TYPE", NULL }; 408 const char *s; 409 int i; 410 411 nodep = eval_getname(funcnp, ex, events, np, globals, 412 croot, arrowp, try, &duped); 413 if (!nodep) 414 return (0); 415 if (nodep->t != T_NAME) { 416 valuep->t = UNDEFINED; 417 return (1); 418 } 419 420 if (nodep->u.name.last->u.name.cp != NULL) { 421 cp = nodep->u.name.last->u.name.cp; 422 } else { 423 path = ipath2str(NULL, ipath(nodep)); 424 cp = config_lookup(croot, path, 0); 425 FREE((void *)path); 426 } 427 if (duped) 428 tree_free(nodep); 429 430 valuep->t = STRING; 431 valuep->v = (uintptr_t)stable(""); 432 if (cp == NULL) 433 return (1); 434 for (i = 0; typestrings[i] != NULL; i++) { 435 s = config_getprop(cp, stable(typestrings[i])); 436 if (s != NULL) { 437 valuep->v = (uintptr_t)stable(s); 438 break; 439 } 440 } 441 return (1); 442 } else if (funcname == L_is_on) { 443 const char *onstrings[] = { "on", "ON", NULL }; 444 const char *truestrings[] = { "yes", "YES", "y", "Y", 445 "true", "TRUE", "t", "T", "1", NULL }; 446 const char *s; 447 int i, j; 448 449 nodep = eval_getname(funcnp, ex, events, np, globals, 450 croot, arrowp, try, &duped); 451 if (!nodep) 452 return (0); 453 if (nodep->t != T_NAME) { 454 valuep->t = UNDEFINED; 455 return (1); 456 } 457 458 if (nodep->u.name.last->u.name.cp != NULL) { 459 cp = nodep->u.name.last->u.name.cp; 460 } else { 461 path = ipath2str(NULL, ipath(nodep)); 462 cp = config_lookup(croot, path, 0); 463 FREE((void *)path); 464 } 465 if (duped) 466 tree_free(nodep); 467 468 valuep->t = UINT64; 469 valuep->v = 0; 470 if (cp == NULL) 471 return (1); 472 for (i = 0; onstrings[i] != NULL; i++) { 473 s = config_getprop(cp, stable(onstrings[i])); 474 if (s != NULL) { 475 s = stable(s); 476 for (j = 0; truestrings[j] != NULL; j++) { 477 if (s == stable(truestrings[j])) { 478 valuep->v = 1; 479 return (1); 480 } 481 } 482 } 483 } 484 return (1); 485 } else if (funcname == L_is_present) { 486 nodep = eval_getname(funcnp, ex, events, np, globals, 487 croot, arrowp, try, &duped); 488 if (!nodep) 489 return (0); 490 if (nodep->t != T_NAME) { 491 valuep->t = UNDEFINED; 492 return (1); 493 } 494 495 if (nodep->u.name.last->u.name.cp != NULL) { 496 cp = nodep->u.name.last->u.name.cp; 497 } else { 498 path = ipath2str(NULL, ipath(nodep)); 499 cp = config_lookup(croot, path, 0); 500 FREE((void *)path); 501 } 502 if (duped) 503 tree_free(nodep); 504 505 valuep->t = UINT64; 506 valuep->v = 0; 507 if (cp != NULL) 508 valuep->v = 1; 509 return (1); 510 } else if (funcname == L_has_fault) { 511 nvlist_t *rsrc = NULL; 512 513 nodep = eval_getname(funcnp, ex, events, np->u.expr.left, 514 globals, croot, arrowp, try, &duped); 515 if (!nodep) 516 return (0); 517 if (nodep->t != T_NAME) { 518 valuep->t = UNDEFINED; 519 return (1); 520 } 521 522 path = ipath2str(NULL, ipath(nodep)); 523 platform_unit_translate(0, croot, TOPO_PROP_RESOURCE, 524 &rsrc, path); 525 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, "has_fault("); 526 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, nodep); 527 out(O_ALTFP|O_VERB2|O_NONL, "(%s), \"%s\") ", path, 528 np->u.expr.right->u.quote.s); 529 FREE((void *)path); 530 if (duped) 531 tree_free(nodep); 532 533 if (rsrc == NULL) { 534 valuep->v = 0; 535 out(O_ALTFP|O_VERB2, "no path"); 536 } else { 537 valuep->v = fmd_nvl_fmri_has_fault(Hdl, rsrc, 538 FMD_HAS_FAULT_RESOURCE, 539 strcmp(np->u.expr.right->u.quote.s, "") == 0 ? 540 NULL : (char *)np->u.expr.right->u.quote.s); 541 out(O_ALTFP|O_VERB2, "returned %lld", valuep->v); 542 nvlist_free(rsrc); 543 } 544 valuep->t = UINT64; 545 return (1); 546 } else if (funcname == L_count) { 547 struct stats *statp; 548 struct istat_entry ent; 549 550 ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t)); 551 552 nodep = np->u.event.epname; 553 if (try) { 554 if (eval_expr(nodep, ex, events, globals, 555 croot, arrowp, try, &val) && val.t == NODEPTR) 556 nodep = (struct node *)(uintptr_t)val.v; 557 else { 558 duped = 1; 559 nodep = eval_dup(nodep, ex, events); 560 } 561 } 562 ent.ename = np->u.event.ename->u.name.s; 563 ent.ipath = ipath(nodep); 564 valuep->t = UINT64; 565 if ((statp = (struct stats *) 566 lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL) 567 valuep->v = 0; 568 else 569 valuep->v = stats_counter_value(statp); 570 if (duped) 571 tree_free(nodep); 572 return (1); 573 } else if (funcname == L_envprop) { 574 outfl(O_DIE, np->file, np->line, 575 "eval_func: %s not yet supported", funcname); 576 } 577 578 if (try) 579 return (0); 580 581 if (funcname == L_fru) { 582 valuep->t = NODEPTR; 583 valuep->v = (uintptr_t)eval_fru(np); 584 return (1); 585 } else if (funcname == L_asru) { 586 valuep->t = NODEPTR; 587 valuep->v = (uintptr_t)eval_asru(np); 588 return (1); 589 } else if (funcname == L_defined) { 590 ASSERTeq(np->t, T_GLOBID, ptree_nodetype2str); 591 valuep->t = UINT64; 592 valuep->v = (lut_lookup(*globals, 593 (void *)np->u.globid.s, NULL) != NULL); 594 return (1); 595 } else if (funcname == L_call) { 596 return (! platform_call(np, globals, croot, arrowp, valuep)); 597 } else if (funcname == L_payloadprop) { 598 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 599 "payloadprop(\"%s\") ", np->u.quote.s); 600 601 if (arrowp->head->myevent->count == 0) { 602 /* 603 * Haven't seen this ereport yet, so must defer 604 */ 605 out(O_ALTFP|O_VERB2, "ereport not yet seen - defer."); 606 return (0); 607 } else if (platform_payloadprop(np, valuep)) { 608 /* platform_payloadprop() returned false */ 609 out(O_ALTFP|O_VERB, "not found."); 610 valuep->t = UNDEFINED; 611 return (1); 612 } else { 613 switch (valuep->t) { 614 case NODEPTR: 615 if (((struct node *)(uintptr_t) 616 (valuep->v))->t == T_NAME) { 617 char *s = ipath2str(NULL, 618 ipath((struct node *) 619 (uintptr_t)valuep->v)); 620 out(O_ALTFP|O_VERB2, 621 "found: \"%s\"", s); 622 FREE(s); 623 } else 624 out(O_ALTFP|O_VERB2, "found: %llu", 625 valuep->v); 626 break; 627 case UINT64: 628 out(O_ALTFP|O_VERB2, "found: %llu", valuep->v); 629 break; 630 case STRING: 631 out(O_ALTFP|O_VERB2, "found: \"%s\"", 632 (char *)(uintptr_t)valuep->v); 633 break; 634 default: 635 out(O_ALTFP|O_VERB2, "found: undefined"); 636 break; 637 } 638 return (1); 639 } 640 } else if (funcname == L_setpayloadprop) { 641 struct evalue *payloadvalp; 642 int alloced = 0; 643 644 ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t)); 645 ASSERTinfo(np->u.expr.left->t == T_QUOTE, 646 ptree_nodetype2str(np->u.expr.left->t)); 647 648 if (!(arrowp->head->myevent->cached_state & REQMNTS_CREDIBLE)) 649 return (0); 650 651 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 652 "setpayloadprop: %s: %s=", 653 arrowp->tail->myevent->enode->u.event.ename->u.name.s, 654 np->u.expr.left->u.quote.s); 655 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right); 656 657 /* 658 * allocate a struct evalue to hold the payload property's 659 * value, unless we've been here already, in which case we 660 * might calculate a different value, but we'll store it 661 * in the already-allocated struct evalue. 662 */ 663 if ((payloadvalp = (struct evalue *)lut_lookup( 664 arrowp->tail->myevent->payloadprops, 665 (void *)np->u.expr.left->u.quote.s, NULL)) == NULL) { 666 payloadvalp = MALLOC(sizeof (*payloadvalp)); 667 alloced = 1; 668 } 669 670 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 671 arrowp, try, payloadvalp)) { 672 out(O_ALTFP|O_VERB2, " (cannot eval)"); 673 if (alloced) 674 FREE(payloadvalp); 675 return (0); 676 } else { 677 if (payloadvalp->t == UNDEFINED) { 678 /* function is always true */ 679 out(O_ALTFP|O_VERB2, " (undefined)"); 680 valuep->t = UINT64; 681 valuep->v = 1; 682 return (1); 683 } 684 if (payloadvalp->t == UINT64) 685 out(O_ALTFP|O_VERB2, 686 " (%llu)", payloadvalp->v); 687 else 688 out(O_ALTFP|O_VERB2, " (\"%s\")", 689 (char *)(uintptr_t)payloadvalp->v); 690 } 691 692 /* add to table of payload properties for current problem */ 693 arrowp->tail->myevent->payloadprops = 694 lut_add(arrowp->tail->myevent->payloadprops, 695 (void *)np->u.expr.left->u.quote.s, 696 (void *)payloadvalp, NULL); 697 698 /* function is always true */ 699 valuep->t = UINT64; 700 valuep->v = 1; 701 return (1); 702 } else if (funcname == L_cat) { 703 int retval = eval_cat(np, ex, events, globals, croot, 704 arrowp, try, valuep); 705 706 outfl(O_ALTFP|O_VERB2, np->file, np->line, 707 "cat: returns %s", (char *)(uintptr_t)valuep->v); 708 return (retval); 709 } else if (funcname == L_setserdn || funcname == L_setserdt || 710 funcname == L_setserdsuffix || funcname == L_setserdincrement) { 711 struct evalue *serdvalp; 712 int alloced = 0; 713 char *str; 714 struct event *flt = arrowp->tail->myevent; 715 716 if (!(arrowp->head->myevent->cached_state & REQMNTS_CREDIBLE)) 717 return (0); 718 719 if (funcname == L_setserdn) 720 str = "n"; 721 else if (funcname == L_setserdt) 722 str = "t"; 723 else if (funcname == L_setserdsuffix) 724 str = "suffix"; 725 else if (funcname == L_setserdincrement) 726 str = "increment"; 727 728 /* 729 * allocate a struct evalue to hold the serd property's 730 * value, unless we've been here already, in which case we 731 * might calculate a different value, but we'll store it 732 * in the already-allocated struct evalue. 733 */ 734 if ((serdvalp = (struct evalue *)lut_lookup(flt->serdprops, 735 (void *)str, (lut_cmp)strcmp)) == NULL) { 736 serdvalp = MALLOC(sizeof (*serdvalp)); 737 alloced = 1; 738 } 739 740 if (!eval_expr(np, ex, events, globals, croot, arrowp, try, 741 serdvalp)) { 742 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 743 "setserd%s: %s: ", str, 744 flt->enode->u.event.ename->u.name.s); 745 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np); 746 out(O_ALTFP|O_VERB2, " (cannot eval)"); 747 if (alloced) 748 FREE(serdvalp); 749 return (0); 750 } else if (serdvalp->t == UNDEFINED) { 751 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 752 "setserd%s: %s: ", str, 753 flt->enode->u.event.ename->u.name.s); 754 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np); 755 out(O_ALTFP|O_VERB2, " (undefined)"); 756 } else { 757 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 758 "setserd%s: %s: ", str, 759 flt->enode->u.event.ename->u.name.s); 760 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np); 761 if ((funcname == L_setserdincrement || 762 funcname == L_setserdn) && serdvalp->t == STRING) { 763 serdvalp->t = UINT64; 764 serdvalp->v = strtoull((char *) 765 (uintptr_t)serdvalp->v, NULL, 0); 766 } 767 if (funcname == L_setserdt && serdvalp->t == UINT64) { 768 int len = snprintf(NULL, 0, "%lldns", 769 serdvalp->v); 770 char *buf = MALLOC(len + 1); 771 772 (void) snprintf(buf, len + 1, "%lldns", 773 serdvalp->v); 774 serdvalp->t = STRING; 775 serdvalp->v = (uintptr_t)stable(buf); 776 FREE(buf); 777 } 778 if (funcname == L_setserdsuffix && 779 serdvalp->t == UINT64) { 780 int len = snprintf(NULL, 0, "%lld", 781 serdvalp->v); 782 char *buf = MALLOC(len + 1); 783 784 (void) snprintf(buf, len + 1, "%lld", 785 serdvalp->v); 786 serdvalp->t = STRING; 787 serdvalp->v = (uintptr_t)stable(buf); 788 FREE(buf); 789 } 790 791 if (serdvalp->t == UINT64) 792 out(O_ALTFP|O_VERB2, " (%llu)", serdvalp->v); 793 else 794 out(O_ALTFP|O_VERB2, " (\"%s\")", 795 (char *)(uintptr_t)serdvalp->v); 796 flt->serdprops = lut_add(flt->serdprops, (void *)str, 797 (void *)serdvalp, (lut_cmp)strcmp); 798 } 799 valuep->t = UINT64; 800 valuep->v = 1; 801 return (1); 802 } else if (funcname == L_payloadprop_defined) { 803 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 804 "payloadprop_defined(\"%s\") ", np->u.quote.s); 805 806 if (arrowp->head->myevent->count == 0) { 807 /* 808 * Haven't seen this ereport yet, so must defer 809 */ 810 out(O_ALTFP|O_VERB2, "ereport not yet seen - defer."); 811 return (0); 812 } else if (platform_payloadprop(np, NULL)) { 813 /* platform_payloadprop() returned false */ 814 valuep->v = 0; 815 out(O_ALTFP|O_VERB2, "not found."); 816 } else { 817 valuep->v = 1; 818 out(O_ALTFP|O_VERB2, "found."); 819 } 820 valuep->t = UINT64; 821 return (1); 822 } else if (funcname == L_payloadprop_contains) { 823 int nvals; 824 struct evalue *vals; 825 struct evalue cmpval; 826 827 ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t)); 828 ASSERTinfo(np->u.expr.left->t == T_QUOTE, 829 ptree_nodetype2str(np->u.expr.left->t)); 830 831 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 832 "payloadprop_contains(\"%s\", ", 833 np->u.expr.left->u.quote.s); 834 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right); 835 out(O_ALTFP|O_VERB2|O_NONL, ") "); 836 837 /* evaluate the expression we're comparing against */ 838 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 839 arrowp, try, &cmpval)) { 840 out(O_ALTFP|O_VERB2|O_NONL, 841 "(cannot eval) "); 842 return (0); 843 } else { 844 switch (cmpval.t) { 845 case UNDEFINED: 846 out(O_ALTFP|O_VERB2, "(undefined type)"); 847 break; 848 849 case UINT64: 850 out(O_ALTFP|O_VERB2, 851 "(%llu) ", cmpval.v); 852 break; 853 854 case STRING: 855 out(O_ALTFP|O_VERB2, 856 "(\"%s\") ", (char *)(uintptr_t)cmpval.v); 857 break; 858 859 case NODEPTR: 860 out(O_ALTFP|O_VERB2|O_NONL, "("); 861 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, 862 (struct node *)(uintptr_t)(cmpval.v)); 863 out(O_ALTFP|O_VERB2, ") "); 864 break; 865 } 866 } 867 868 /* get the payload values and check for a match */ 869 vals = platform_payloadprop_values(np->u.expr.left->u.quote.s, 870 &nvals); 871 valuep->t = UINT64; 872 valuep->v = 0; 873 if (arrowp->head->myevent->count == 0) { 874 /* 875 * Haven't seen this ereport yet, so must defer 876 */ 877 out(O_ALTFP|O_VERB2, "ereport not yet seen - defer."); 878 return (0); 879 } else if (nvals == 0) { 880 out(O_ALTFP|O_VERB2, "not found."); 881 return (1); 882 } else { 883 struct evalue preval; 884 int i; 885 886 out(O_ALTFP|O_VERB2|O_NONL, "found %d values ", nvals); 887 888 for (i = 0; i < nvals; i++) { 889 890 preval.t = vals[i].t; 891 preval.v = vals[i].v; 892 893 if (check_expr_args(&vals[i], &cmpval, 894 UNDEFINED, np)) 895 continue; 896 897 /* 898 * If we auto-converted the value to a 899 * string, we need to free the 900 * original tree value. 901 */ 902 if (preval.t == NODEPTR && 903 ((struct node *)(uintptr_t)(preval.v))->t == 904 T_NAME) { 905 tree_free((struct node *)(uintptr_t) 906 preval.v); 907 } 908 909 if (vals[i].v == cmpval.v) { 910 valuep->v = 1; 911 break; 912 } 913 } 914 915 if (valuep->v) 916 out(O_ALTFP|O_VERB2, "match."); 917 else 918 out(O_ALTFP|O_VERB2, "no match."); 919 920 for (i = 0; i < nvals; i++) { 921 if (vals[i].t == NODEPTR) { 922 tree_free((struct node *)(uintptr_t) 923 vals[i].v); 924 break; 925 } 926 } 927 FREE(vals); 928 } 929 return (1); 930 } else if (funcname == L_confcall) { 931 return (!platform_confcall(np, globals, croot, arrowp, valuep)); 932 } else 933 outfl(O_DIE, np->file, np->line, 934 "eval_func: unexpected func: %s", funcname); 935 /*NOTREACHED*/ 936 return (0); 937 } 938 939 /* 940 * defines for u.expr.temp - these are used for T_OR and T_AND so that if 941 * we worked out that part of the expression was true or false during an 942 * earlier eval_expr, then we don't need to dup that part. 943 */ 944 945 #define EXPR_TEMP_BOTH_UNK 0 946 #define EXPR_TEMP_LHS_UNK 1 947 #define EXPR_TEMP_RHS_UNK 2 948 949 static struct node * 950 eval_dup(struct node *np, struct lut *ex, struct node *events[]) 951 { 952 struct node *newnp; 953 954 if (np == NULL) 955 return (NULL); 956 957 switch (np->t) { 958 case T_GLOBID: 959 return (tree_globid(np->u.globid.s, np->file, np->line)); 960 961 case T_ASSIGN: 962 case T_CONDIF: 963 case T_CONDELSE: 964 case T_NE: 965 case T_EQ: 966 case T_LT: 967 case T_LE: 968 case T_GT: 969 case T_GE: 970 case T_BITAND: 971 case T_BITOR: 972 case T_BITXOR: 973 case T_BITNOT: 974 case T_LSHIFT: 975 case T_RSHIFT: 976 case T_NOT: 977 case T_ADD: 978 case T_SUB: 979 case T_MUL: 980 case T_DIV: 981 case T_MOD: 982 return (tree_expr(np->t, 983 eval_dup(np->u.expr.left, ex, events), 984 eval_dup(np->u.expr.right, ex, events))); 985 case T_LIST: 986 case T_AND: 987 switch (np->u.expr.temp) { 988 case EXPR_TEMP_LHS_UNK: 989 return (eval_dup(np->u.expr.left, ex, events)); 990 case EXPR_TEMP_RHS_UNK: 991 return (eval_dup(np->u.expr.right, ex, events)); 992 default: 993 return (tree_expr(np->t, 994 eval_dup(np->u.expr.left, ex, events), 995 eval_dup(np->u.expr.right, ex, events))); 996 } 997 998 case T_OR: 999 switch (np->u.expr.temp) { 1000 case EXPR_TEMP_LHS_UNK: 1001 return (eval_dup(np->u.expr.left, ex, events)); 1002 case EXPR_TEMP_RHS_UNK: 1003 return (eval_dup(np->u.expr.right, ex, events)); 1004 default: 1005 return (tree_expr(T_OR, 1006 eval_dup(np->u.expr.left, ex, events), 1007 eval_dup(np->u.expr.right, ex, events))); 1008 } 1009 1010 case T_NAME: { 1011 struct iterinfo *iterinfop; 1012 int got_matchf = 0; 1013 int got_matcht = 0; 1014 struct evalue value; 1015 struct node *np1f, *np2f, *np1t, *np2t, *retp = NULL; 1016 struct node *npstart, *npcont, *npend, *npref, *newnp, *nprest; 1017 1018 /* 1019 * Check if we already have a match of the nonwildcarded path 1020 * in oldepname (check both to and from events). 1021 */ 1022 for (np1f = np, np2f = events[0]->u.event.oldepname; 1023 np1f != NULL && np2f != NULL; 1024 np1f = np1f->u.name.next, np2f = np2f->u.name.next) { 1025 if (strcmp(np1f->u.name.s, np2f->u.name.s) != 0) 1026 break; 1027 if (np1f->u.name.child->t != np2f->u.name.child->t) 1028 break; 1029 if (np1f->u.name.child->t == T_NUM && 1030 np1f->u.name.child->u.ull != 1031 np2f->u.name.child->u.ull) 1032 break; 1033 if (np1f->u.name.child->t == T_NAME && 1034 strcmp(np1f->u.name.child->u.name.s, 1035 np2f->u.name.child->u.name.s) != 0) 1036 break; 1037 got_matchf++; 1038 } 1039 for (np1t = np, np2t = events[1]->u.event.oldepname; 1040 np1t != NULL && np2t != NULL; 1041 np1t = np1t->u.name.next, np2t = np2t->u.name.next) { 1042 if (strcmp(np1t->u.name.s, np2t->u.name.s) != 0) 1043 break; 1044 if (np1t->u.name.child->t != np2t->u.name.child->t) 1045 break; 1046 if (np1t->u.name.child->t == T_NUM && 1047 np1t->u.name.child->u.ull != 1048 np2t->u.name.child->u.ull) 1049 break; 1050 if (np1t->u.name.child->t == T_NAME && 1051 strcmp(np1t->u.name.child->u.name.s, 1052 np2t->u.name.child->u.name.s) != 0) 1053 break; 1054 got_matcht++; 1055 } 1056 nprest = np; 1057 if (got_matchf || got_matcht) { 1058 /* 1059 * so we are wildcarding. Copy ewname in full, plus 1060 * matching section of oldepname. Use whichever gives 1061 * the closest match. 1062 */ 1063 if (got_matchf > got_matcht) { 1064 npstart = events[0]->u.event.ewname; 1065 npcont = events[0]->u.event.oldepname; 1066 npend = np2f; 1067 nprest = np1f; 1068 } else { 1069 npstart = events[1]->u.event.ewname; 1070 npcont = events[1]->u.event.oldepname; 1071 npend = np2t; 1072 nprest = np1t; 1073 } 1074 for (npref = npstart; npref != NULL; 1075 npref = npref->u.name.next) { 1076 newnp = newnode(T_NAME, np->file, np->line); 1077 newnp->u.name.t = npref->u.name.t; 1078 newnp->u.name.s = npref->u.name.s; 1079 newnp->u.name.last = newnp; 1080 newnp->u.name.it = npref->u.name.it; 1081 newnp->u.name.cp = npref->u.name.cp; 1082 newnp->u.name.child = 1083 newnode(T_NUM, np->file, np->line); 1084 if (eval_expr(npref->u.name.child, ex, events, 1085 NULL, NULL, NULL, 1, &value) == 0 || 1086 value.t != UINT64) { 1087 outfl(O_DIE, np->file, np->line, 1088 "eval_dup: could not resolve " 1089 "iterator of %s", np->u.name.s); 1090 } 1091 newnp->u.name.child->u.ull = value.v; 1092 if (retp == NULL) { 1093 retp = newnp; 1094 } else { 1095 retp->u.name.last->u.name.next = newnp; 1096 retp->u.name.last = newnp; 1097 } 1098 } 1099 for (npref = npcont; npref != NULL && npref != npend; 1100 npref = npref->u.name.next) { 1101 newnp = newnode(T_NAME, np->file, np->line); 1102 newnp->u.name.t = npref->u.name.t; 1103 newnp->u.name.s = npref->u.name.s; 1104 newnp->u.name.last = newnp; 1105 newnp->u.name.it = npref->u.name.it; 1106 newnp->u.name.cp = npref->u.name.cp; 1107 newnp->u.name.child = 1108 newnode(T_NUM, np->file, np->line); 1109 if (eval_expr(npref->u.name.child, ex, events, 1110 NULL, NULL, NULL, 1, &value) == 0 || 1111 value.t != UINT64) { 1112 outfl(O_DIE, np->file, np->line, 1113 "eval_dup: could not resolve " 1114 "iterator of %s", np->u.name.s); 1115 } 1116 newnp->u.name.child->u.ull = value.v; 1117 if (retp == NULL) { 1118 retp = newnp; 1119 } else { 1120 retp->u.name.last->u.name.next = newnp; 1121 retp->u.name.last = newnp; 1122 } 1123 } 1124 } else { 1125 /* 1126 * not wildcarding - check if explicit iterator 1127 */ 1128 iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL); 1129 if (iterinfop != NULL) { 1130 /* explicit iterator; not part of pathname */ 1131 newnp = newnode(T_NUM, np->file, np->line); 1132 newnp->u.ull = iterinfop->num; 1133 return (newnp); 1134 } 1135 } 1136 1137 /* 1138 * finally, whether wildcarding or not, we need to copy the 1139 * remaining part of the path (if any). This must be defined 1140 * absolutely (no more expansion/wildcarding). 1141 */ 1142 for (npref = nprest; npref != NULL; 1143 npref = npref->u.name.next) { 1144 newnp = newnode(T_NAME, np->file, np->line); 1145 newnp->u.name.t = npref->u.name.t; 1146 newnp->u.name.s = npref->u.name.s; 1147 newnp->u.name.last = newnp; 1148 newnp->u.name.it = npref->u.name.it; 1149 newnp->u.name.cp = npref->u.name.cp; 1150 newnp->u.name.child = 1151 newnode(T_NUM, np->file, np->line); 1152 if (eval_expr(npref->u.name.child, ex, events, 1153 NULL, NULL, NULL, 1, &value) == 0 || 1154 value.t != UINT64) { 1155 outfl(O_DIE, np->file, np->line, 1156 "eval_dup: could not resolve " 1157 "iterator of %s", np->u.name.s); 1158 } 1159 newnp->u.name.child->u.ull = value.v; 1160 if (retp == NULL) { 1161 retp = newnp; 1162 } else { 1163 retp->u.name.last->u.name.next = newnp; 1164 retp->u.name.last = newnp; 1165 } 1166 } 1167 return (retp); 1168 } 1169 1170 case T_EVENT: 1171 newnp = newnode(T_NAME, np->file, np->line); 1172 1173 newnp->u.name.t = np->u.event.ename->u.name.t; 1174 newnp->u.name.s = np->u.event.ename->u.name.s; 1175 newnp->u.name.it = np->u.event.ename->u.name.it; 1176 newnp->u.name.last = newnp; 1177 1178 return (tree_event(newnp, 1179 eval_dup(np->u.event.epname, ex, events), 1180 eval_dup(np->u.event.eexprlist, ex, events))); 1181 1182 case T_FUNC: 1183 return (tree_func(np->u.func.s, 1184 eval_dup(np->u.func.arglist, ex, events), 1185 np->file, np->line)); 1186 1187 case T_QUOTE: 1188 newnp = newnode(T_QUOTE, np->file, np->line); 1189 newnp->u.quote.s = np->u.quote.s; 1190 return (newnp); 1191 1192 case T_NUM: 1193 newnp = newnode(T_NUM, np->file, np->line); 1194 newnp->u.ull = np->u.ull; 1195 return (newnp); 1196 1197 case T_TIMEVAL: 1198 newnp = newnode(T_TIMEVAL, np->file, np->line); 1199 newnp->u.ull = np->u.ull; 1200 return (newnp); 1201 1202 default: 1203 outfl(O_DIE, np->file, np->line, 1204 "eval_dup: unexpected node type: %s", 1205 ptree_nodetype2str(np->t)); 1206 } 1207 /*NOTREACHED*/ 1208 return (0); 1209 } 1210 1211 /* 1212 * eval_potential -- see if constraint is potentially true 1213 * 1214 * this function is used at instance tree creation time to see if 1215 * any constraints are already known to be false. if this function 1216 * returns false, then the constraint will always be false and there's 1217 * no need to include the propagation arrow in the instance tree. 1218 * 1219 * if this routine returns true, either the constraint is known to 1220 * be always true (so there's no point in attaching the constraint 1221 * to the propagation arrow in the instance tree), or the constraint 1222 * contains "deferred" expressions like global variables or poller calls 1223 * and so it must be evaluated during calls to fme_eval(). in this last 1224 * case, where a constraint needs to be attached to the propagation arrow 1225 * in the instance tree, this routine returns a newly created constraint 1226 * in *newc where all the non-deferred things have been filled in. 1227 * 1228 * so in summary: 1229 * 1230 * return of false: constraint can never be true, *newc will be NULL. 1231 * 1232 * return of true with *newc unchanged: constraint will always be true. 1233 * 1234 * return of true with *newc changed: use new constraint in *newc. 1235 * 1236 * the lookup table for all explicit iterators, ex, is passed in. 1237 * 1238 * *newc can either be NULL on entry, or if can contain constraints from 1239 * previous calls to eval_potential() (i.e. for building up an instance 1240 * tree constraint from several potential constraints). if *newc already 1241 * contains constraints, anything added to it will be joined by adding 1242 * a T_AND node at the top of *newc. 1243 */ 1244 int 1245 eval_potential(struct node *np, struct lut *ex, struct node *events[], 1246 struct node **newc, struct config *croot) 1247 { 1248 struct node *newnp; 1249 struct evalue value; 1250 1251 if (eval_expr(np, ex, events, NULL, croot, NULL, 1, &value) == 0) { 1252 /* 1253 * couldn't eval expression because 1254 * it contains deferred items. make 1255 * a duplicate expression with all the 1256 * non-deferred items expanded. 1257 */ 1258 newnp = eval_dup(np, ex, events); 1259 1260 if (*newc == NULL) { 1261 /* 1262 * constraint is potentially true if deferred 1263 * expression in newnp is true. *newc was NULL 1264 * so new constraint is just the one in newnp. 1265 */ 1266 *newc = newnp; 1267 return (1); 1268 } else { 1269 /* 1270 * constraint is potentially true if deferred 1271 * expression in newnp is true. *newc already 1272 * contained a constraint so add an AND with the 1273 * constraint in newnp. 1274 */ 1275 *newc = tree_expr(T_AND, *newc, newnp); 1276 return (1); 1277 } 1278 } else if (value.t == UNDEFINED) { 1279 /* constraint can never be true */ 1280 return (0); 1281 } else if (value.t == UINT64 && value.v == 0) { 1282 /* constraint can never be true */ 1283 return (0); 1284 } else { 1285 /* constraint is always true (nothing deferred to eval) */ 1286 return (1); 1287 } 1288 } 1289 1290 static int 1291 check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype, 1292 struct node *np) 1293 { 1294 /* auto-convert T_NAMES to strings */ 1295 if (lp->t == NODEPTR && ((struct node *)(uintptr_t)(lp->v))->t == 1296 T_NAME) { 1297 char *s = ipath2str(NULL, 1298 ipath((struct node *)(uintptr_t)lp->v)); 1299 lp->t = STRING; 1300 lp->v = (uintptr_t)stable(s); 1301 FREE(s); 1302 out(O_ALTFP|O_VERB2, "convert lhs path to \"%s\"", 1303 (char *)(uintptr_t)lp->v); 1304 } 1305 if (rp != NULL && 1306 rp->t == NODEPTR && ((struct node *)(uintptr_t)(rp->v))->t == 1307 T_NAME) { 1308 char *s = ipath2str(NULL, 1309 ipath((struct node *)(uintptr_t)rp->v)); 1310 rp->t = STRING; 1311 rp->v = (uintptr_t)stable(s); 1312 FREE(s); 1313 out(O_ALTFP|O_VERB2, "convert rhs path to \"%s\"", 1314 (char *)(uintptr_t)rp->v); 1315 } 1316 1317 /* auto-convert numbers to strings */ 1318 if (dtype == STRING) { 1319 if (lp->t == UINT64) { 1320 int len = snprintf(NULL, 0, "%llx", lp->v); 1321 char *s = MALLOC(len + 1); 1322 1323 (void) snprintf(s, len + 1, "%llx", lp->v); 1324 lp->t = STRING; 1325 lp->v = (uintptr_t)stable(s); 1326 FREE(s); 1327 } 1328 if (rp != NULL && rp->t == UINT64) { 1329 int len = snprintf(NULL, 0, "%llx", rp->v); 1330 char *s = MALLOC(len + 1); 1331 1332 (void) snprintf(s, len + 1, "%llx", rp->v); 1333 rp->t = STRING; 1334 rp->v = (uintptr_t)stable(s); 1335 FREE(s); 1336 } 1337 } 1338 1339 /* auto-convert strings to numbers */ 1340 if (dtype == UINT64) { 1341 if (lp->t == STRING) { 1342 lp->t = UINT64; 1343 lp->v = strtoull((char *)(uintptr_t)lp->v, NULL, 0); 1344 } 1345 if (rp != NULL && rp->t == STRING) { 1346 rp->t = UINT64; 1347 rp->v = strtoull((char *)(uintptr_t)rp->v, NULL, 0); 1348 } 1349 } 1350 1351 if (dtype != UNDEFINED && lp->t != dtype) { 1352 outfl(O_DIE, np->file, np->line, 1353 "invalid datatype of argument for operation %s", 1354 ptree_nodetype2str(np->t)); 1355 /* NOTREACHED */ 1356 return (1); 1357 } 1358 1359 if (rp != NULL && lp->t != rp->t) { 1360 outfl(O_DIE, np->file, np->line, 1361 "mismatch in datatype of arguments for operation %s", 1362 ptree_nodetype2str(np->t)); 1363 /* NOTREACHED */ 1364 return (1); 1365 } 1366 1367 return (0); 1368 } 1369 1370 /* 1371 * eval_expr -- evaluate expression into *valuep 1372 * 1373 * the meaning of the return value depends on the input value of try. 1374 * 1375 * for try == 1: if any deferred items are encounted, bail out and return 1376 * false. returns true if we made it through entire expression without 1377 * hitting any deferred items. 1378 * 1379 * for try == 0: return true if all operations were performed successfully. 1380 * return false if otherwise. for example, any of the following conditions 1381 * will result in a false return value: 1382 * - attempted use of an uninitialized global variable 1383 * - failure in function evaluation 1384 * - illegal arithmetic operation (argument out of range) 1385 */ 1386 int 1387 eval_expr(struct node *np, struct lut *ex, struct node *events[], 1388 struct lut **globals, struct config *croot, struct arrow *arrowp, 1389 int try, struct evalue *valuep) 1390 { 1391 struct evalue *gval; 1392 struct evalue lval; 1393 struct evalue rval; 1394 1395 if (np == NULL) { 1396 valuep->t = UINT64; 1397 valuep->v = 1; /* no constraint means "true" */ 1398 return (1); 1399 } 1400 1401 valuep->t = UNDEFINED; 1402 1403 switch (np->t) { 1404 case T_GLOBID: 1405 if (try) 1406 return (0); 1407 1408 /* 1409 * only handle case of getting (and not setting) the value 1410 * of a global variable 1411 */ 1412 gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL); 1413 if (gval == NULL) { 1414 return (0); 1415 } else { 1416 valuep->t = gval->t; 1417 valuep->v = gval->v; 1418 return (1); 1419 } 1420 1421 case T_ASSIGN: 1422 if (try) 1423 return (0); 1424 1425 /* 1426 * first evaluate rhs, then try to store value in lhs which 1427 * should be a global variable 1428 */ 1429 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1430 arrowp, try, &rval)) 1431 return (0); 1432 1433 ASSERT(np->u.expr.left->t == T_GLOBID); 1434 gval = lut_lookup(*globals, 1435 (void *)np->u.expr.left->u.globid.s, NULL); 1436 1437 if (gval == NULL) { 1438 gval = MALLOC(sizeof (*gval)); 1439 *globals = lut_add(*globals, 1440 (void *) np->u.expr.left->u.globid.s, gval, NULL); 1441 } 1442 1443 gval->t = rval.t; 1444 gval->v = rval.v; 1445 1446 if (gval->t == UINT64) { 1447 out(O_ALTFP|O_VERB2, 1448 "assign $%s=%llu", 1449 np->u.expr.left->u.globid.s, gval->v); 1450 } else { 1451 out(O_ALTFP|O_VERB2, 1452 "assign $%s=\"%s\"", 1453 np->u.expr.left->u.globid.s, 1454 (char *)(uintptr_t)gval->v); 1455 } 1456 1457 /* 1458 * but always return true -- an assignment should not 1459 * cause a constraint to be false. 1460 */ 1461 valuep->t = UINT64; 1462 valuep->v = 1; 1463 return (1); 1464 1465 case T_EQ: 1466 #define IMPLICIT_ASSIGN_IN_EQ 1467 #ifdef IMPLICIT_ASSIGN_IN_EQ 1468 /* 1469 * if lhs is an uninitialized global variable, perform 1470 * an assignment. 1471 * 1472 * one insidious side effect of implicit assignment is 1473 * that the "==" operator does not return a Boolean if 1474 * implicit assignment was performed. 1475 */ 1476 if (try == 0 && 1477 np->u.expr.left->t == T_GLOBID && 1478 (gval = lut_lookup(*globals, 1479 (void *)np->u.expr.left->u.globid.s, NULL)) == NULL) { 1480 if (!eval_expr(np->u.expr.right, ex, events, globals, 1481 croot, arrowp, try, &rval)) 1482 return (0); 1483 1484 gval = MALLOC(sizeof (*gval)); 1485 *globals = lut_add(*globals, 1486 (void *) np->u.expr.left->u.globid.s, 1487 gval, NULL); 1488 1489 gval->t = rval.t; 1490 gval->v = rval.v; 1491 valuep->t = rval.t; 1492 valuep->v = rval.v; 1493 return (1); 1494 } 1495 #endif /* IMPLICIT_ASSIGN_IN_EQ */ 1496 1497 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1498 arrowp, try, &lval)) 1499 return (0); 1500 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1501 arrowp, try, &rval)) 1502 return (0); 1503 if (rval.t == UINT64 || lval.t == UINT64) { 1504 if (check_expr_args(&lval, &rval, UINT64, np)) 1505 return (0); 1506 } else { 1507 if (check_expr_args(&lval, &rval, UNDEFINED, np)) 1508 return (0); 1509 } 1510 1511 valuep->t = UINT64; 1512 valuep->v = (lval.v == rval.v); 1513 return (1); 1514 1515 case T_LT: 1516 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1517 arrowp, try, &lval)) 1518 return (0); 1519 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1520 arrowp, try, &rval)) 1521 return (0); 1522 if (check_expr_args(&lval, &rval, UINT64, np)) 1523 return (0); 1524 1525 valuep->t = UINT64; 1526 valuep->v = (lval.v < rval.v); 1527 return (1); 1528 1529 case T_LE: 1530 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1531 arrowp, try, &lval)) 1532 return (0); 1533 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1534 arrowp, try, &rval)) 1535 return (0); 1536 if (check_expr_args(&lval, &rval, UINT64, np)) 1537 return (0); 1538 1539 valuep->t = UINT64; 1540 valuep->v = (lval.v <= rval.v); 1541 return (1); 1542 1543 case T_GT: 1544 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1545 arrowp, try, &lval)) 1546 return (0); 1547 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1548 arrowp, try, &rval)) 1549 return (0); 1550 if (check_expr_args(&lval, &rval, UINT64, np)) 1551 return (0); 1552 1553 valuep->t = UINT64; 1554 valuep->v = (lval.v > rval.v); 1555 return (1); 1556 1557 case T_GE: 1558 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1559 arrowp, try, &lval)) 1560 return (0); 1561 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1562 arrowp, try, &rval)) 1563 return (0); 1564 if (check_expr_args(&lval, &rval, UINT64, np)) 1565 return (0); 1566 1567 valuep->t = UINT64; 1568 valuep->v = (lval.v >= rval.v); 1569 return (1); 1570 1571 case T_BITAND: 1572 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1573 arrowp, try, &lval)) 1574 return (0); 1575 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1576 arrowp, try, &rval)) 1577 return (0); 1578 if (check_expr_args(&lval, &rval, UINT64, np)) 1579 return (0); 1580 1581 valuep->t = lval.t; 1582 valuep->v = (lval.v & rval.v); 1583 return (1); 1584 1585 case T_BITOR: 1586 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1587 arrowp, try, &lval)) 1588 return (0); 1589 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1590 arrowp, try, &rval)) 1591 return (0); 1592 if (check_expr_args(&lval, &rval, UINT64, np)) 1593 return (0); 1594 1595 valuep->t = lval.t; 1596 valuep->v = (lval.v | rval.v); 1597 return (1); 1598 1599 case T_BITXOR: 1600 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1601 arrowp, try, &lval)) 1602 return (0); 1603 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1604 arrowp, try, &rval)) 1605 return (0); 1606 if (check_expr_args(&lval, &rval, UINT64, np)) 1607 return (0); 1608 1609 valuep->t = lval.t; 1610 valuep->v = (lval.v ^ rval.v); 1611 return (1); 1612 1613 case T_BITNOT: 1614 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1615 arrowp, try, &lval)) 1616 return (0); 1617 ASSERT(np->u.expr.right == NULL); 1618 if (check_expr_args(&lval, NULL, UINT64, np)) 1619 return (0); 1620 1621 valuep->t = UINT64; 1622 valuep->v = ~ lval.v; 1623 return (1); 1624 1625 case T_LSHIFT: 1626 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1627 arrowp, try, &lval)) 1628 return (0); 1629 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1630 arrowp, try, &rval)) 1631 return (0); 1632 if (check_expr_args(&lval, &rval, UINT64, np)) 1633 return (0); 1634 1635 valuep->t = UINT64; 1636 valuep->v = (lval.v << rval.v); 1637 return (1); 1638 1639 case T_RSHIFT: 1640 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1641 arrowp, try, &lval)) 1642 return (0); 1643 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1644 arrowp, try, &rval)) 1645 return (0); 1646 if (check_expr_args(&lval, &rval, UINT64, np)) 1647 return (0); 1648 1649 valuep->t = UINT64; 1650 valuep->v = (lval.v >> rval.v); 1651 return (1); 1652 1653 case T_CONDIF: { 1654 struct node *retnp; 1655 int dotrue = 0; 1656 1657 /* 1658 * evaluate 1659 * expression ? stmtA [ : stmtB ] 1660 * 1661 * first see if expression is true or false, then determine 1662 * if stmtA (or stmtB, if it exists) should be evaluated. 1663 * 1664 * "dotrue = 1" means stmtA should be evaluated. 1665 */ 1666 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1667 arrowp, try, &lval)) 1668 return (0); 1669 1670 if (lval.t != UNDEFINED && lval.v != 0) 1671 dotrue = 1; 1672 1673 ASSERT(np->u.expr.right != NULL); 1674 if (np->u.expr.right->t == T_CONDELSE) { 1675 if (dotrue) 1676 retnp = np->u.expr.right->u.expr.left; 1677 else 1678 retnp = np->u.expr.right->u.expr.right; 1679 } else { 1680 /* no ELSE clause */ 1681 if (dotrue) 1682 retnp = np->u.expr.right; 1683 else { 1684 outfl(O_DIE, np->file, np->line, 1685 "eval_expr: missing condelse"); 1686 } 1687 } 1688 1689 if (!eval_expr(retnp, ex, events, globals, croot, 1690 arrowp, try, valuep)) 1691 return (0); 1692 return (1); 1693 } 1694 1695 case T_CONDELSE: 1696 /* 1697 * shouldn't get here, since T_CONDELSE is supposed to be 1698 * evaluated as part of T_CONDIF 1699 */ 1700 out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s", 1701 ptree_nodetype2str(np->t)); 1702 /*NOTREACHED*/ 1703 break; 1704 1705 case T_NE: 1706 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1707 arrowp, try, &lval)) 1708 return (0); 1709 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1710 arrowp, try, &rval)) 1711 return (0); 1712 if (rval.t == UINT64 || lval.t == UINT64) { 1713 if (check_expr_args(&lval, &rval, UINT64, np)) 1714 return (0); 1715 } else { 1716 if (check_expr_args(&lval, &rval, UNDEFINED, np)) 1717 return (0); 1718 } 1719 1720 valuep->t = UINT64; 1721 valuep->v = (lval.v != rval.v); 1722 return (1); 1723 1724 case T_LIST: 1725 case T_AND: 1726 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1727 arrowp, try, valuep)) { 1728 /* 1729 * if lhs is unknown, still check rhs. If that 1730 * is false we can return false irrespective of lhs 1731 */ 1732 if (!try) { 1733 np->u.expr.temp = EXPR_TEMP_BOTH_UNK; 1734 return (0); 1735 } 1736 if (!eval_expr(np->u.expr.right, ex, events, globals, 1737 croot, arrowp, try, valuep)) { 1738 np->u.expr.temp = EXPR_TEMP_BOTH_UNK; 1739 return (0); 1740 } 1741 if (valuep->v != 0) { 1742 np->u.expr.temp = EXPR_TEMP_LHS_UNK; 1743 return (0); 1744 } 1745 } 1746 if (valuep->v == 0) { 1747 valuep->t = UINT64; 1748 return (1); 1749 } 1750 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1751 arrowp, try, valuep)) { 1752 np->u.expr.temp = EXPR_TEMP_RHS_UNK; 1753 return (0); 1754 } 1755 valuep->t = UINT64; 1756 valuep->v = valuep->v == 0 ? 0 : 1; 1757 return (1); 1758 1759 case T_OR: 1760 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1761 arrowp, try, valuep)) { 1762 /* 1763 * if lhs is unknown, still check rhs. If that 1764 * is true we can return true irrespective of lhs 1765 */ 1766 if (!try) { 1767 np->u.expr.temp = EXPR_TEMP_BOTH_UNK; 1768 return (0); 1769 } 1770 if (!eval_expr(np->u.expr.right, ex, events, globals, 1771 croot, arrowp, try, valuep)) { 1772 np->u.expr.temp = EXPR_TEMP_BOTH_UNK; 1773 return (0); 1774 } 1775 if (valuep->v == 0) { 1776 np->u.expr.temp = EXPR_TEMP_LHS_UNK; 1777 return (0); 1778 } 1779 } 1780 if (valuep->v != 0) { 1781 valuep->t = UINT64; 1782 valuep->v = 1; 1783 return (1); 1784 } 1785 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1786 arrowp, try, valuep)) { 1787 np->u.expr.temp = EXPR_TEMP_RHS_UNK; 1788 return (0); 1789 } 1790 valuep->t = UINT64; 1791 valuep->v = valuep->v == 0 ? 0 : 1; 1792 return (1); 1793 1794 case T_NOT: 1795 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1796 arrowp, try, valuep)) 1797 return (0); 1798 valuep->t = UINT64; 1799 valuep->v = ! valuep->v; 1800 return (1); 1801 1802 case T_ADD: 1803 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1804 arrowp, try, &lval)) 1805 return (0); 1806 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1807 arrowp, try, &rval)) 1808 return (0); 1809 if (check_expr_args(&lval, &rval, UINT64, np)) 1810 return (0); 1811 1812 valuep->t = lval.t; 1813 valuep->v = lval.v + rval.v; 1814 return (1); 1815 1816 case T_SUB: 1817 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1818 arrowp, try, &lval)) 1819 return (0); 1820 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1821 arrowp, try, &rval)) 1822 return (0); 1823 if (check_expr_args(&lval, &rval, UINT64, np)) 1824 return (0); 1825 1826 /* since valuep is unsigned, return false if lval.v < rval.v */ 1827 if (lval.v < rval.v) { 1828 outfl(O_DIE, np->file, np->line, 1829 "eval_expr: T_SUB result is out of range"); 1830 } 1831 1832 valuep->t = lval.t; 1833 valuep->v = lval.v - rval.v; 1834 return (1); 1835 1836 case T_MUL: 1837 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1838 arrowp, try, &lval)) 1839 return (0); 1840 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1841 arrowp, try, &rval)) 1842 return (0); 1843 if (check_expr_args(&lval, &rval, UINT64, np)) 1844 return (0); 1845 1846 valuep->t = lval.t; 1847 valuep->v = lval.v * rval.v; 1848 return (1); 1849 1850 case T_DIV: 1851 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1852 arrowp, try, &lval)) 1853 return (0); 1854 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1855 arrowp, try, &rval)) 1856 return (0); 1857 if (check_expr_args(&lval, &rval, UINT64, np)) 1858 return (0); 1859 1860 /* return false if dividing by zero */ 1861 if (rval.v == 0) { 1862 outfl(O_DIE, np->file, np->line, 1863 "eval_expr: T_DIV division by zero"); 1864 } 1865 1866 valuep->t = lval.t; 1867 valuep->v = lval.v / rval.v; 1868 return (1); 1869 1870 case T_MOD: 1871 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1872 arrowp, try, &lval)) 1873 return (0); 1874 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1875 arrowp, try, &rval)) 1876 return (0); 1877 if (check_expr_args(&lval, &rval, UINT64, np)) 1878 return (0); 1879 1880 /* return false if dividing by zero */ 1881 if (rval.v == 0) { 1882 outfl(O_DIE, np->file, np->line, 1883 "eval_expr: T_MOD division by zero"); 1884 } 1885 1886 valuep->t = lval.t; 1887 valuep->v = lval.v % rval.v; 1888 return (1); 1889 1890 case T_NAME: 1891 if (try) { 1892 struct iterinfo *iterinfop; 1893 struct node *np1, *np2; 1894 int i, gotmatch = 0; 1895 1896 /* 1897 * Check if we have an exact match of the nonwildcarded 1898 * path in oldepname - if so we can just use the 1899 * full wildcarded path in epname. 1900 */ 1901 for (i = 0; i < 1; i++) { 1902 for (np1 = np, 1903 np2 = events[i]->u.event.oldepname; 1904 np1 != NULL && np2 != NULL; 1905 np1 = np1->u.name.next, 1906 np2 = np2->u.name.next) { 1907 if (strcmp(np1->u.name.s, 1908 np2->u.name.s) != 0) 1909 break; 1910 if (np1->u.name.child->t != 1911 np2->u.name.child->t) 1912 break; 1913 if (np1->u.name.child->t == T_NUM && 1914 np1->u.name.child->u.ull != 1915 np2->u.name.child->u.ull) 1916 break; 1917 if (np1->u.name.child->t == T_NAME && 1918 strcmp(np1->u.name.child->u.name.s, 1919 np2->u.name.child->u.name.s) != 0) 1920 break; 1921 gotmatch++; 1922 } 1923 if (np1 == NULL && np2 == NULL) { 1924 valuep->t = NODEPTR; 1925 valuep->v = (uintptr_t) 1926 events[i]->u.event.epname; 1927 return (1); 1928 } 1929 } 1930 if (!gotmatch) { 1931 /* 1932 * we're not wildcarding. However at 1933 * itree_create() time, we can also expand 1934 * simple iterators - so check for those. 1935 */ 1936 iterinfop = lut_lookup(ex, (void *)np->u.name.s, 1937 NULL); 1938 if (iterinfop != NULL) { 1939 valuep->t = UINT64; 1940 valuep->v = 1941 (unsigned long long)iterinfop->num; 1942 return (1); 1943 } 1944 } 1945 /* 1946 * For anything else we'll have to wait for eval_dup(). 1947 */ 1948 return (0); 1949 } 1950 1951 /* return address of struct node */ 1952 valuep->t = NODEPTR; 1953 valuep->v = (uintptr_t)np; 1954 return (1); 1955 1956 case T_QUOTE: 1957 valuep->t = STRING; 1958 valuep->v = (uintptr_t)np->u.quote.s; 1959 return (1); 1960 1961 case T_FUNC: 1962 return (eval_func(np, ex, events, np->u.func.arglist, 1963 globals, croot, arrowp, try, valuep)); 1964 1965 case T_NUM: 1966 case T_TIMEVAL: 1967 valuep->t = UINT64; 1968 valuep->v = np->u.ull; 1969 return (1); 1970 1971 default: 1972 outfl(O_DIE, np->file, np->line, 1973 "eval_expr: unexpected node type: %s", 1974 ptree_nodetype2str(np->t)); 1975 } 1976 /*NOTREACHED*/ 1977 return (0); 1978 } 1979 1980 /* 1981 * eval_fru() and eval_asru() don't do much, but are called from a number 1982 * of places. 1983 */ 1984 static struct node * 1985 eval_fru(struct node *np) 1986 { 1987 ASSERT(np->t == T_NAME); 1988 return (np); 1989 } 1990 1991 static struct node * 1992 eval_asru(struct node *np) 1993 { 1994 ASSERT(np->t == T_NAME); 1995 return (np); 1996 } 1997