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