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 2009 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 } 541 valuep->t = UINT64; 542 return (1); 543 } else if (funcname == L_count) { 544 struct stats *statp; 545 struct istat_entry ent; 546 547 ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t)); 548 549 nodep = np->u.event.epname; 550 if (try) { 551 if (eval_expr(nodep, ex, events, globals, 552 croot, arrowp, try, &val) && val.t == NODEPTR) 553 nodep = (struct node *)(uintptr_t)val.v; 554 else { 555 duped = 1; 556 nodep = eval_dup(nodep, ex, events); 557 } 558 } 559 ent.ename = np->u.event.ename->u.name.s; 560 ent.ipath = ipath(nodep); 561 valuep->t = UINT64; 562 if ((statp = (struct stats *) 563 lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL) 564 valuep->v = 0; 565 else 566 valuep->v = stats_counter_value(statp); 567 if (duped) 568 tree_free(nodep); 569 return (1); 570 } else if (funcname == L_envprop) { 571 outfl(O_DIE, np->file, np->line, 572 "eval_func: %s not yet supported", funcname); 573 } 574 575 if (try) 576 return (0); 577 578 if (funcname == L_fru) { 579 valuep->t = NODEPTR; 580 valuep->v = (uintptr_t)eval_fru(np); 581 return (1); 582 } else if (funcname == L_asru) { 583 valuep->t = NODEPTR; 584 valuep->v = (uintptr_t)eval_asru(np); 585 return (1); 586 } else if (funcname == L_defined) { 587 ASSERTeq(np->t, T_GLOBID, ptree_nodetype2str); 588 valuep->t = UINT64; 589 valuep->v = (lut_lookup(*globals, 590 (void *)np->u.globid.s, NULL) != NULL); 591 return (1); 592 } else if (funcname == L_call) { 593 return (! platform_call(np, globals, croot, arrowp, valuep)); 594 } else if (funcname == L_payloadprop) { 595 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 596 "payloadprop(\"%s\") ", np->u.quote.s); 597 598 if (arrowp->head->myevent->count == 0) { 599 /* 600 * Haven't seen this ereport yet, so must defer 601 */ 602 out(O_ALTFP|O_VERB2, "ereport not yet seen - defer."); 603 return (0); 604 } else if (platform_payloadprop(np, valuep)) { 605 /* platform_payloadprop() returned false */ 606 out(O_ALTFP|O_VERB, "not found."); 607 valuep->t = UNDEFINED; 608 return (1); 609 } else { 610 switch (valuep->t) { 611 case NODEPTR: 612 if (((struct node *)(uintptr_t) 613 (valuep->v))->t == T_NAME) { 614 char *s = ipath2str(NULL, 615 ipath((struct node *) 616 (uintptr_t)valuep->v)); 617 out(O_ALTFP|O_VERB2, 618 "found: \"%s\"", s); 619 FREE(s); 620 } else 621 out(O_ALTFP|O_VERB2, "found: %llu", 622 valuep->v); 623 break; 624 case UINT64: 625 out(O_ALTFP|O_VERB2, "found: %llu", valuep->v); 626 break; 627 case STRING: 628 out(O_ALTFP|O_VERB2, "found: \"%s\"", 629 (char *)(uintptr_t)valuep->v); 630 break; 631 default: 632 out(O_ALTFP|O_VERB2, "found: undefined"); 633 break; 634 } 635 return (1); 636 } 637 } else if (funcname == L_setpayloadprop) { 638 struct evalue *payloadvalp; 639 int alloced = 0; 640 641 ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t)); 642 ASSERTinfo(np->u.expr.left->t == T_QUOTE, 643 ptree_nodetype2str(np->u.expr.left->t)); 644 645 if (!(arrowp->head->myevent->cached_state & REQMNTS_CREDIBLE)) 646 return (0); 647 648 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 649 "setpayloadprop: %s: %s=", 650 arrowp->tail->myevent->enode->u.event.ename->u.name.s, 651 np->u.expr.left->u.quote.s); 652 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right); 653 654 /* 655 * allocate a struct evalue to hold the payload property's 656 * value, unless we've been here already, in which case we 657 * might calculate a different value, but we'll store it 658 * in the already-allocated struct evalue. 659 */ 660 if ((payloadvalp = (struct evalue *)lut_lookup( 661 arrowp->tail->myevent->payloadprops, 662 (void *)np->u.expr.left->u.quote.s, NULL)) == NULL) { 663 payloadvalp = MALLOC(sizeof (*payloadvalp)); 664 alloced = 1; 665 } 666 667 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 668 arrowp, try, payloadvalp)) { 669 out(O_ALTFP|O_VERB2, " (cannot eval)"); 670 if (alloced) 671 FREE(payloadvalp); 672 return (0); 673 } else { 674 if (payloadvalp->t == UNDEFINED) { 675 /* function is always true */ 676 out(O_ALTFP|O_VERB2, " (undefined)"); 677 valuep->t = UINT64; 678 valuep->v = 1; 679 return (1); 680 } 681 if (payloadvalp->t == UINT64) 682 out(O_ALTFP|O_VERB2, 683 " (%llu)", payloadvalp->v); 684 else 685 out(O_ALTFP|O_VERB2, " (\"%s\")", 686 (char *)(uintptr_t)payloadvalp->v); 687 } 688 689 /* add to table of payload properties for current problem */ 690 arrowp->tail->myevent->payloadprops = 691 lut_add(arrowp->tail->myevent->payloadprops, 692 (void *)np->u.expr.left->u.quote.s, 693 (void *)payloadvalp, NULL); 694 695 /* function is always true */ 696 valuep->t = UINT64; 697 valuep->v = 1; 698 return (1); 699 } else if (funcname == L_cat) { 700 int retval = eval_cat(np, ex, events, globals, croot, 701 arrowp, try, valuep); 702 703 outfl(O_ALTFP|O_VERB2, np->file, np->line, 704 "cat: returns %s", (char *)(uintptr_t)valuep->v); 705 return (retval); 706 } else if (funcname == L_setserdn || funcname == L_setserdt || 707 funcname == L_setserdsuffix || funcname == L_setserdincrement) { 708 struct evalue *serdvalp; 709 int alloced = 0; 710 char *str; 711 struct event *flt = arrowp->tail->myevent; 712 713 if (!(arrowp->head->myevent->cached_state & REQMNTS_CREDIBLE)) 714 return (0); 715 716 if (funcname == L_setserdn) 717 str = "n"; 718 else if (funcname == L_setserdt) 719 str = "t"; 720 else if (funcname == L_setserdsuffix) 721 str = "suffix"; 722 else if (funcname == L_setserdincrement) 723 str = "increment"; 724 725 /* 726 * allocate a struct evalue to hold the serd property's 727 * value, unless we've been here already, in which case we 728 * might calculate a different value, but we'll store it 729 * in the already-allocated struct evalue. 730 */ 731 if ((serdvalp = (struct evalue *)lut_lookup(flt->serdprops, 732 (void *)str, (lut_cmp)strcmp)) == NULL) { 733 serdvalp = MALLOC(sizeof (*serdvalp)); 734 alloced = 1; 735 } 736 737 if (!eval_expr(np, ex, events, globals, croot, arrowp, try, 738 serdvalp)) { 739 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 740 "setserd%s: %s: ", str, 741 flt->enode->u.event.ename->u.name.s); 742 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np); 743 out(O_ALTFP|O_VERB2, " (cannot eval)"); 744 if (alloced) 745 FREE(serdvalp); 746 return (0); 747 } else if (serdvalp->t == UNDEFINED) { 748 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 749 "setserd%s: %s: ", str, 750 flt->enode->u.event.ename->u.name.s); 751 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np); 752 out(O_ALTFP|O_VERB2, " (undefined)"); 753 } else { 754 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 755 "setserd%s: %s: ", str, 756 flt->enode->u.event.ename->u.name.s); 757 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np); 758 if ((funcname == L_setserdincrement || 759 funcname == L_setserdn) && serdvalp->t == STRING) { 760 serdvalp->t = UINT64; 761 serdvalp->v = strtoull((char *) 762 (uintptr_t)serdvalp->v, NULL, 0); 763 } 764 if (funcname == L_setserdt && serdvalp->t == UINT64) { 765 int len = snprintf(NULL, 0, "%lldns", 766 serdvalp->v); 767 char *buf = MALLOC(len + 1); 768 769 (void) snprintf(buf, len + 1, "%lldns", 770 serdvalp->v); 771 serdvalp->t = STRING; 772 serdvalp->v = (uintptr_t)stable(buf); 773 FREE(buf); 774 } 775 if (funcname == L_setserdsuffix && 776 serdvalp->t == UINT64) { 777 int len = snprintf(NULL, 0, "%lld", 778 serdvalp->v); 779 char *buf = MALLOC(len + 1); 780 781 (void) snprintf(buf, len + 1, "%lld", 782 serdvalp->v); 783 serdvalp->t = STRING; 784 serdvalp->v = (uintptr_t)stable(buf); 785 FREE(buf); 786 } 787 788 if (serdvalp->t == UINT64) 789 out(O_ALTFP|O_VERB2, " (%llu)", serdvalp->v); 790 else 791 out(O_ALTFP|O_VERB2, " (\"%s\")", 792 (char *)(uintptr_t)serdvalp->v); 793 flt->serdprops = lut_add(flt->serdprops, (void *)str, 794 (void *)serdvalp, (lut_cmp)strcmp); 795 } 796 valuep->t = UINT64; 797 valuep->v = 1; 798 return (1); 799 } else if (funcname == L_payloadprop_defined) { 800 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 801 "payloadprop_defined(\"%s\") ", np->u.quote.s); 802 803 if (arrowp->head->myevent->count == 0) { 804 /* 805 * Haven't seen this ereport yet, so must defer 806 */ 807 out(O_ALTFP|O_VERB2, "ereport not yet seen - defer."); 808 return (0); 809 } else if (platform_payloadprop(np, NULL)) { 810 /* platform_payloadprop() returned false */ 811 valuep->v = 0; 812 out(O_ALTFP|O_VERB2, "not found."); 813 } else { 814 valuep->v = 1; 815 out(O_ALTFP|O_VERB2, "found."); 816 } 817 valuep->t = UINT64; 818 return (1); 819 } else if (funcname == L_payloadprop_contains) { 820 int nvals; 821 struct evalue *vals; 822 struct evalue cmpval; 823 824 ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t)); 825 ASSERTinfo(np->u.expr.left->t == T_QUOTE, 826 ptree_nodetype2str(np->u.expr.left->t)); 827 828 outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 829 "payloadprop_contains(\"%s\", ", 830 np->u.expr.left->u.quote.s); 831 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right); 832 out(O_ALTFP|O_VERB2|O_NONL, ") "); 833 834 /* evaluate the expression we're comparing against */ 835 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 836 arrowp, try, &cmpval)) { 837 out(O_ALTFP|O_VERB2|O_NONL, 838 "(cannot eval) "); 839 return (0); 840 } else { 841 switch (cmpval.t) { 842 case UNDEFINED: 843 out(O_ALTFP|O_VERB2, "(undefined type)"); 844 break; 845 846 case UINT64: 847 out(O_ALTFP|O_VERB2, 848 "(%llu) ", cmpval.v); 849 break; 850 851 case STRING: 852 out(O_ALTFP|O_VERB2, 853 "(\"%s\") ", (char *)(uintptr_t)cmpval.v); 854 break; 855 856 case NODEPTR: 857 out(O_ALTFP|O_VERB2|O_NONL, "("); 858 ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, 859 (struct node *)(uintptr_t)(cmpval.v)); 860 out(O_ALTFP|O_VERB2, ") "); 861 break; 862 } 863 } 864 865 /* get the payload values and check for a match */ 866 vals = platform_payloadprop_values(np->u.expr.left->u.quote.s, 867 &nvals); 868 valuep->t = UINT64; 869 valuep->v = 0; 870 if (arrowp->head->myevent->count == 0) { 871 /* 872 * Haven't seen this ereport yet, so must defer 873 */ 874 out(O_ALTFP|O_VERB2, "ereport not yet seen - defer."); 875 return (0); 876 } else if (nvals == 0) { 877 out(O_ALTFP|O_VERB2, "not found."); 878 return (1); 879 } else { 880 struct evalue preval; 881 int i; 882 883 out(O_ALTFP|O_VERB2|O_NONL, "found %d values ", nvals); 884 885 for (i = 0; i < nvals; i++) { 886 887 preval.t = vals[i].t; 888 preval.v = vals[i].v; 889 890 if (check_expr_args(&vals[i], &cmpval, 891 UNDEFINED, np)) 892 continue; 893 894 /* 895 * If we auto-converted the value to a 896 * string, we need to free the 897 * original tree value. 898 */ 899 if (preval.t == NODEPTR && 900 ((struct node *)(uintptr_t)(preval.v))->t == 901 T_NAME) { 902 tree_free((struct node *)(uintptr_t) 903 preval.v); 904 } 905 906 if (vals[i].v == cmpval.v) { 907 valuep->v = 1; 908 break; 909 } 910 } 911 912 if (valuep->v) 913 out(O_ALTFP|O_VERB2, "match."); 914 else 915 out(O_ALTFP|O_VERB2, "no match."); 916 917 for (i = 0; i < nvals; i++) { 918 if (vals[i].t == NODEPTR) { 919 tree_free((struct node *)(uintptr_t) 920 vals[i].v); 921 break; 922 } 923 } 924 FREE(vals); 925 } 926 return (1); 927 } else if (funcname == L_confcall) { 928 return (!platform_confcall(np, globals, croot, arrowp, valuep)); 929 } else 930 outfl(O_DIE, np->file, np->line, 931 "eval_func: unexpected func: %s", funcname); 932 /*NOTREACHED*/ 933 return (0); 934 } 935 936 /* 937 * defines for u.expr.temp - these are used for T_OR and T_AND so that if 938 * we worked out that part of the expression was true or false during an 939 * earlier eval_expr, then we don't need to dup that part. 940 */ 941 942 #define EXPR_TEMP_BOTH_UNK 0 943 #define EXPR_TEMP_LHS_UNK 1 944 #define EXPR_TEMP_RHS_UNK 2 945 946 static struct node * 947 eval_dup(struct node *np, struct lut *ex, struct node *events[]) 948 { 949 struct node *newnp; 950 951 if (np == NULL) 952 return (NULL); 953 954 switch (np->t) { 955 case T_GLOBID: 956 return (tree_globid(np->u.globid.s, np->file, np->line)); 957 958 case T_ASSIGN: 959 case T_CONDIF: 960 case T_CONDELSE: 961 case T_NE: 962 case T_EQ: 963 case T_LT: 964 case T_LE: 965 case T_GT: 966 case T_GE: 967 case T_BITAND: 968 case T_BITOR: 969 case T_BITXOR: 970 case T_BITNOT: 971 case T_LSHIFT: 972 case T_RSHIFT: 973 case T_NOT: 974 case T_ADD: 975 case T_SUB: 976 case T_MUL: 977 case T_DIV: 978 case T_MOD: 979 return (tree_expr(np->t, 980 eval_dup(np->u.expr.left, ex, events), 981 eval_dup(np->u.expr.right, ex, events))); 982 case T_LIST: 983 case T_AND: 984 switch (np->u.expr.temp) { 985 case EXPR_TEMP_LHS_UNK: 986 return (eval_dup(np->u.expr.left, ex, events)); 987 case EXPR_TEMP_RHS_UNK: 988 return (eval_dup(np->u.expr.right, ex, events)); 989 default: 990 return (tree_expr(np->t, 991 eval_dup(np->u.expr.left, ex, events), 992 eval_dup(np->u.expr.right, ex, events))); 993 } 994 995 case T_OR: 996 switch (np->u.expr.temp) { 997 case EXPR_TEMP_LHS_UNK: 998 return (eval_dup(np->u.expr.left, ex, events)); 999 case EXPR_TEMP_RHS_UNK: 1000 return (eval_dup(np->u.expr.right, ex, events)); 1001 default: 1002 return (tree_expr(T_OR, 1003 eval_dup(np->u.expr.left, ex, events), 1004 eval_dup(np->u.expr.right, ex, events))); 1005 } 1006 1007 case T_NAME: { 1008 struct iterinfo *iterinfop; 1009 int got_matchf = 0; 1010 int got_matcht = 0; 1011 struct evalue value; 1012 struct node *np1f, *np2f, *np1t, *np2t, *retp = NULL; 1013 struct node *npstart, *npcont, *npend, *npref, *newnp, *nprest; 1014 1015 /* 1016 * Check if we already have a match of the nonwildcarded path 1017 * in oldepname (check both to and from events). 1018 */ 1019 for (np1f = np, np2f = events[0]->u.event.oldepname; 1020 np1f != NULL && np2f != NULL; 1021 np1f = np1f->u.name.next, np2f = np2f->u.name.next) { 1022 if (strcmp(np1f->u.name.s, np2f->u.name.s) != 0) 1023 break; 1024 if (np1f->u.name.child->t != np2f->u.name.child->t) 1025 break; 1026 if (np1f->u.name.child->t == T_NUM && 1027 np1f->u.name.child->u.ull != 1028 np2f->u.name.child->u.ull) 1029 break; 1030 if (np1f->u.name.child->t == T_NAME && 1031 strcmp(np1f->u.name.child->u.name.s, 1032 np2f->u.name.child->u.name.s) != 0) 1033 break; 1034 got_matchf++; 1035 } 1036 for (np1t = np, np2t = events[1]->u.event.oldepname; 1037 np1t != NULL && np2t != NULL; 1038 np1t = np1t->u.name.next, np2t = np2t->u.name.next) { 1039 if (strcmp(np1t->u.name.s, np2t->u.name.s) != 0) 1040 break; 1041 if (np1t->u.name.child->t != np2t->u.name.child->t) 1042 break; 1043 if (np1t->u.name.child->t == T_NUM && 1044 np1t->u.name.child->u.ull != 1045 np2t->u.name.child->u.ull) 1046 break; 1047 if (np1t->u.name.child->t == T_NAME && 1048 strcmp(np1t->u.name.child->u.name.s, 1049 np2t->u.name.child->u.name.s) != 0) 1050 break; 1051 got_matcht++; 1052 } 1053 nprest = np; 1054 if (got_matchf || got_matcht) { 1055 /* 1056 * so we are wildcarding. Copy ewname in full, plus 1057 * matching section of oldepname. Use whichever gives 1058 * the closest match. 1059 */ 1060 if (got_matchf > got_matcht) { 1061 npstart = events[0]->u.event.ewname; 1062 npcont = events[0]->u.event.oldepname; 1063 npend = np2f; 1064 nprest = np1f; 1065 } else { 1066 npstart = events[1]->u.event.ewname; 1067 npcont = events[1]->u.event.oldepname; 1068 npend = np2t; 1069 nprest = np1t; 1070 } 1071 for (npref = npstart; npref != NULL; 1072 npref = npref->u.name.next) { 1073 newnp = newnode(T_NAME, np->file, np->line); 1074 newnp->u.name.t = npref->u.name.t; 1075 newnp->u.name.s = npref->u.name.s; 1076 newnp->u.name.last = newnp; 1077 newnp->u.name.it = npref->u.name.it; 1078 newnp->u.name.cp = npref->u.name.cp; 1079 newnp->u.name.child = 1080 newnode(T_NUM, np->file, np->line); 1081 if (eval_expr(npref->u.name.child, ex, events, 1082 NULL, NULL, NULL, 1, &value) == 0 || 1083 value.t != UINT64) { 1084 outfl(O_DIE, np->file, np->line, 1085 "eval_dup: could not resolve " 1086 "iterator of %s", np->u.name.s); 1087 } 1088 newnp->u.name.child->u.ull = value.v; 1089 if (retp == NULL) { 1090 retp = newnp; 1091 } else { 1092 retp->u.name.last->u.name.next = newnp; 1093 retp->u.name.last = newnp; 1094 } 1095 } 1096 for (npref = npcont; npref != NULL && npref != npend; 1097 npref = npref->u.name.next) { 1098 newnp = newnode(T_NAME, np->file, np->line); 1099 newnp->u.name.t = npref->u.name.t; 1100 newnp->u.name.s = npref->u.name.s; 1101 newnp->u.name.last = newnp; 1102 newnp->u.name.it = npref->u.name.it; 1103 newnp->u.name.cp = npref->u.name.cp; 1104 newnp->u.name.child = 1105 newnode(T_NUM, np->file, np->line); 1106 if (eval_expr(npref->u.name.child, ex, events, 1107 NULL, NULL, NULL, 1, &value) == 0 || 1108 value.t != UINT64) { 1109 outfl(O_DIE, np->file, np->line, 1110 "eval_dup: could not resolve " 1111 "iterator of %s", np->u.name.s); 1112 } 1113 newnp->u.name.child->u.ull = value.v; 1114 if (retp == NULL) { 1115 retp = newnp; 1116 } else { 1117 retp->u.name.last->u.name.next = newnp; 1118 retp->u.name.last = newnp; 1119 } 1120 } 1121 } else { 1122 /* 1123 * not wildcarding - check if explicit iterator 1124 */ 1125 iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL); 1126 if (iterinfop != NULL) { 1127 /* explicit iterator; not part of pathname */ 1128 newnp = newnode(T_NUM, np->file, np->line); 1129 newnp->u.ull = iterinfop->num; 1130 return (newnp); 1131 } 1132 } 1133 1134 /* 1135 * finally, whether wildcarding or not, we need to copy the 1136 * remaining part of the path (if any). This must be defined 1137 * absolutely (no more expansion/wildcarding). 1138 */ 1139 for (npref = nprest; npref != NULL; 1140 npref = npref->u.name.next) { 1141 newnp = newnode(T_NAME, np->file, np->line); 1142 newnp->u.name.t = npref->u.name.t; 1143 newnp->u.name.s = npref->u.name.s; 1144 newnp->u.name.last = newnp; 1145 newnp->u.name.it = npref->u.name.it; 1146 newnp->u.name.cp = npref->u.name.cp; 1147 newnp->u.name.child = 1148 newnode(T_NUM, np->file, np->line); 1149 if (eval_expr(npref->u.name.child, ex, events, 1150 NULL, NULL, NULL, 1, &value) == 0 || 1151 value.t != UINT64) { 1152 outfl(O_DIE, np->file, np->line, 1153 "eval_dup: could not resolve " 1154 "iterator of %s", np->u.name.s); 1155 } 1156 newnp->u.name.child->u.ull = value.v; 1157 if (retp == NULL) { 1158 retp = newnp; 1159 } else { 1160 retp->u.name.last->u.name.next = newnp; 1161 retp->u.name.last = newnp; 1162 } 1163 } 1164 return (retp); 1165 } 1166 1167 case T_EVENT: 1168 newnp = newnode(T_NAME, np->file, np->line); 1169 1170 newnp->u.name.t = np->u.event.ename->u.name.t; 1171 newnp->u.name.s = np->u.event.ename->u.name.s; 1172 newnp->u.name.it = np->u.event.ename->u.name.it; 1173 newnp->u.name.last = newnp; 1174 1175 return (tree_event(newnp, 1176 eval_dup(np->u.event.epname, ex, events), 1177 eval_dup(np->u.event.eexprlist, ex, events))); 1178 1179 case T_FUNC: 1180 return (tree_func(np->u.func.s, 1181 eval_dup(np->u.func.arglist, ex, events), 1182 np->file, np->line)); 1183 1184 case T_QUOTE: 1185 newnp = newnode(T_QUOTE, np->file, np->line); 1186 newnp->u.quote.s = np->u.quote.s; 1187 return (newnp); 1188 1189 case T_NUM: 1190 newnp = newnode(T_NUM, np->file, np->line); 1191 newnp->u.ull = np->u.ull; 1192 return (newnp); 1193 1194 case T_TIMEVAL: 1195 newnp = newnode(T_TIMEVAL, np->file, np->line); 1196 newnp->u.ull = np->u.ull; 1197 return (newnp); 1198 1199 default: 1200 outfl(O_DIE, np->file, np->line, 1201 "eval_dup: unexpected node type: %s", 1202 ptree_nodetype2str(np->t)); 1203 } 1204 /*NOTREACHED*/ 1205 return (0); 1206 } 1207 1208 /* 1209 * eval_potential -- see if constraint is potentially true 1210 * 1211 * this function is used at instance tree creation time to see if 1212 * any constraints are already known to be false. if this function 1213 * returns false, then the constraint will always be false and there's 1214 * no need to include the propagation arrow in the instance tree. 1215 * 1216 * if this routine returns true, either the constraint is known to 1217 * be always true (so there's no point in attaching the constraint 1218 * to the propagation arrow in the instance tree), or the constraint 1219 * contains "deferred" expressions like global variables or poller calls 1220 * and so it must be evaluated during calls to fme_eval(). in this last 1221 * case, where a constraint needs to be attached to the propagation arrow 1222 * in the instance tree, this routine returns a newly created constraint 1223 * in *newc where all the non-deferred things have been filled in. 1224 * 1225 * so in summary: 1226 * 1227 * return of false: constraint can never be true, *newc will be NULL. 1228 * 1229 * return of true with *newc unchanged: constraint will always be true. 1230 * 1231 * return of true with *newc changed: use new constraint in *newc. 1232 * 1233 * the lookup table for all explicit iterators, ex, is passed in. 1234 * 1235 * *newc can either be NULL on entry, or if can contain constraints from 1236 * previous calls to eval_potential() (i.e. for building up an instance 1237 * tree constraint from several potential constraints). if *newc already 1238 * contains constraints, anything added to it will be joined by adding 1239 * a T_AND node at the top of *newc. 1240 */ 1241 int 1242 eval_potential(struct node *np, struct lut *ex, struct node *events[], 1243 struct node **newc, struct config *croot) 1244 { 1245 struct node *newnp; 1246 struct evalue value; 1247 1248 if (eval_expr(np, ex, events, NULL, croot, NULL, 1, &value) == 0) { 1249 /* 1250 * couldn't eval expression because 1251 * it contains deferred items. make 1252 * a duplicate expression with all the 1253 * non-deferred items expanded. 1254 */ 1255 newnp = eval_dup(np, ex, events); 1256 1257 if (*newc == NULL) { 1258 /* 1259 * constraint is potentially true if deferred 1260 * expression in newnp is true. *newc was NULL 1261 * so new constraint is just the one in newnp. 1262 */ 1263 *newc = newnp; 1264 return (1); 1265 } else { 1266 /* 1267 * constraint is potentially true if deferred 1268 * expression in newnp is true. *newc already 1269 * contained a constraint so add an AND with the 1270 * constraint in newnp. 1271 */ 1272 *newc = tree_expr(T_AND, *newc, newnp); 1273 return (1); 1274 } 1275 } else if (value.t == UNDEFINED) { 1276 /* constraint can never be true */ 1277 return (0); 1278 } else if (value.t == UINT64 && value.v == 0) { 1279 /* constraint can never be true */ 1280 return (0); 1281 } else { 1282 /* constraint is always true (nothing deferred to eval) */ 1283 return (1); 1284 } 1285 } 1286 1287 static int 1288 check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype, 1289 struct node *np) 1290 { 1291 /* auto-convert T_NAMES to strings */ 1292 if (lp->t == NODEPTR && ((struct node *)(uintptr_t)(lp->v))->t == 1293 T_NAME) { 1294 char *s = ipath2str(NULL, 1295 ipath((struct node *)(uintptr_t)lp->v)); 1296 lp->t = STRING; 1297 lp->v = (uintptr_t)stable(s); 1298 FREE(s); 1299 out(O_ALTFP|O_VERB2, "convert lhs path to \"%s\"", 1300 (char *)(uintptr_t)lp->v); 1301 } 1302 if (rp != NULL && 1303 rp->t == NODEPTR && ((struct node *)(uintptr_t)(rp->v))->t == 1304 T_NAME) { 1305 char *s = ipath2str(NULL, 1306 ipath((struct node *)(uintptr_t)rp->v)); 1307 rp->t = STRING; 1308 rp->v = (uintptr_t)stable(s); 1309 FREE(s); 1310 out(O_ALTFP|O_VERB2, "convert rhs path to \"%s\"", 1311 (char *)(uintptr_t)rp->v); 1312 } 1313 1314 /* auto-convert numbers to strings */ 1315 if (dtype == STRING) { 1316 if (lp->t == UINT64) { 1317 int len = snprintf(NULL, 0, "%llx", lp->v); 1318 char *s = MALLOC(len + 1); 1319 1320 (void) snprintf(s, len + 1, "%llx", lp->v); 1321 lp->t = STRING; 1322 lp->v = (uintptr_t)stable(s); 1323 FREE(s); 1324 } 1325 if (rp != NULL && rp->t == UINT64) { 1326 int len = snprintf(NULL, 0, "%llx", rp->v); 1327 char *s = MALLOC(len + 1); 1328 1329 (void) snprintf(s, len + 1, "%llx", rp->v); 1330 rp->t = STRING; 1331 rp->v = (uintptr_t)stable(s); 1332 FREE(s); 1333 } 1334 } 1335 1336 /* auto-convert strings to numbers */ 1337 if (dtype == UINT64) { 1338 if (lp->t == STRING) { 1339 lp->t = UINT64; 1340 lp->v = strtoull((char *)(uintptr_t)lp->v, NULL, 0); 1341 } 1342 if (rp != NULL && rp->t == STRING) { 1343 rp->t = UINT64; 1344 rp->v = strtoull((char *)(uintptr_t)rp->v, NULL, 0); 1345 } 1346 } 1347 1348 if (dtype != UNDEFINED && lp->t != dtype) { 1349 outfl(O_DIE, np->file, np->line, 1350 "invalid datatype of argument for operation %s", 1351 ptree_nodetype2str(np->t)); 1352 /* NOTREACHED */ 1353 return (1); 1354 } 1355 1356 if (rp != NULL && lp->t != rp->t) { 1357 outfl(O_DIE, np->file, np->line, 1358 "mismatch in datatype of arguments for operation %s", 1359 ptree_nodetype2str(np->t)); 1360 /* NOTREACHED */ 1361 return (1); 1362 } 1363 1364 return (0); 1365 } 1366 1367 /* 1368 * eval_expr -- evaluate expression into *valuep 1369 * 1370 * the meaning of the return value depends on the input value of try. 1371 * 1372 * for try == 1: if any deferred items are encounted, bail out and return 1373 * false. returns true if we made it through entire expression without 1374 * hitting any deferred items. 1375 * 1376 * for try == 0: return true if all operations were performed successfully. 1377 * return false if otherwise. for example, any of the following conditions 1378 * will result in a false return value: 1379 * - attempted use of an uninitialized global variable 1380 * - failure in function evaluation 1381 * - illegal arithmetic operation (argument out of range) 1382 */ 1383 int 1384 eval_expr(struct node *np, struct lut *ex, struct node *events[], 1385 struct lut **globals, struct config *croot, struct arrow *arrowp, 1386 int try, struct evalue *valuep) 1387 { 1388 struct evalue *gval; 1389 struct evalue lval; 1390 struct evalue rval; 1391 1392 if (np == NULL) { 1393 valuep->t = UINT64; 1394 valuep->v = 1; /* no constraint means "true" */ 1395 return (1); 1396 } 1397 1398 valuep->t = UNDEFINED; 1399 1400 switch (np->t) { 1401 case T_GLOBID: 1402 if (try) 1403 return (0); 1404 1405 /* 1406 * only handle case of getting (and not setting) the value 1407 * of a global variable 1408 */ 1409 gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL); 1410 if (gval == NULL) { 1411 return (0); 1412 } else { 1413 valuep->t = gval->t; 1414 valuep->v = gval->v; 1415 return (1); 1416 } 1417 1418 case T_ASSIGN: 1419 if (try) 1420 return (0); 1421 1422 /* 1423 * first evaluate rhs, then try to store value in lhs which 1424 * should be a global variable 1425 */ 1426 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1427 arrowp, try, &rval)) 1428 return (0); 1429 1430 ASSERT(np->u.expr.left->t == T_GLOBID); 1431 gval = lut_lookup(*globals, 1432 (void *)np->u.expr.left->u.globid.s, NULL); 1433 1434 if (gval == NULL) { 1435 gval = MALLOC(sizeof (*gval)); 1436 *globals = lut_add(*globals, 1437 (void *) np->u.expr.left->u.globid.s, gval, NULL); 1438 } 1439 1440 gval->t = rval.t; 1441 gval->v = rval.v; 1442 1443 if (gval->t == UINT64) { 1444 out(O_ALTFP|O_VERB2, 1445 "assign $%s=%llu", 1446 np->u.expr.left->u.globid.s, gval->v); 1447 } else { 1448 out(O_ALTFP|O_VERB2, 1449 "assign $%s=\"%s\"", 1450 np->u.expr.left->u.globid.s, 1451 (char *)(uintptr_t)gval->v); 1452 } 1453 1454 /* 1455 * but always return true -- an assignment should not 1456 * cause a constraint to be false. 1457 */ 1458 valuep->t = UINT64; 1459 valuep->v = 1; 1460 return (1); 1461 1462 case T_EQ: 1463 #define IMPLICIT_ASSIGN_IN_EQ 1464 #ifdef IMPLICIT_ASSIGN_IN_EQ 1465 /* 1466 * if lhs is an uninitialized global variable, perform 1467 * an assignment. 1468 * 1469 * one insidious side effect of implicit assignment is 1470 * that the "==" operator does not return a Boolean if 1471 * implicit assignment was performed. 1472 */ 1473 if (try == 0 && 1474 np->u.expr.left->t == T_GLOBID && 1475 (gval = lut_lookup(*globals, 1476 (void *)np->u.expr.left->u.globid.s, NULL)) == NULL) { 1477 if (!eval_expr(np->u.expr.right, ex, events, globals, 1478 croot, arrowp, try, &rval)) 1479 return (0); 1480 1481 gval = MALLOC(sizeof (*gval)); 1482 *globals = lut_add(*globals, 1483 (void *) np->u.expr.left->u.globid.s, 1484 gval, NULL); 1485 1486 gval->t = rval.t; 1487 gval->v = rval.v; 1488 valuep->t = rval.t; 1489 valuep->v = rval.v; 1490 return (1); 1491 } 1492 #endif /* IMPLICIT_ASSIGN_IN_EQ */ 1493 1494 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1495 arrowp, try, &lval)) 1496 return (0); 1497 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1498 arrowp, try, &rval)) 1499 return (0); 1500 if (rval.t == UINT64 || lval.t == UINT64) { 1501 if (check_expr_args(&lval, &rval, UINT64, np)) 1502 return (0); 1503 } else { 1504 if (check_expr_args(&lval, &rval, UNDEFINED, np)) 1505 return (0); 1506 } 1507 1508 valuep->t = UINT64; 1509 valuep->v = (lval.v == rval.v); 1510 return (1); 1511 1512 case T_LT: 1513 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1514 arrowp, try, &lval)) 1515 return (0); 1516 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1517 arrowp, try, &rval)) 1518 return (0); 1519 if (check_expr_args(&lval, &rval, UINT64, np)) 1520 return (0); 1521 1522 valuep->t = UINT64; 1523 valuep->v = (lval.v < rval.v); 1524 return (1); 1525 1526 case T_LE: 1527 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1528 arrowp, try, &lval)) 1529 return (0); 1530 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1531 arrowp, try, &rval)) 1532 return (0); 1533 if (check_expr_args(&lval, &rval, UINT64, np)) 1534 return (0); 1535 1536 valuep->t = UINT64; 1537 valuep->v = (lval.v <= rval.v); 1538 return (1); 1539 1540 case T_GT: 1541 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1542 arrowp, try, &lval)) 1543 return (0); 1544 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1545 arrowp, try, &rval)) 1546 return (0); 1547 if (check_expr_args(&lval, &rval, UINT64, np)) 1548 return (0); 1549 1550 valuep->t = UINT64; 1551 valuep->v = (lval.v > rval.v); 1552 return (1); 1553 1554 case T_GE: 1555 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1556 arrowp, try, &lval)) 1557 return (0); 1558 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1559 arrowp, try, &rval)) 1560 return (0); 1561 if (check_expr_args(&lval, &rval, UINT64, np)) 1562 return (0); 1563 1564 valuep->t = UINT64; 1565 valuep->v = (lval.v >= rval.v); 1566 return (1); 1567 1568 case T_BITAND: 1569 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1570 arrowp, try, &lval)) 1571 return (0); 1572 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1573 arrowp, try, &rval)) 1574 return (0); 1575 if (check_expr_args(&lval, &rval, UINT64, np)) 1576 return (0); 1577 1578 valuep->t = lval.t; 1579 valuep->v = (lval.v & rval.v); 1580 return (1); 1581 1582 case T_BITOR: 1583 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1584 arrowp, try, &lval)) 1585 return (0); 1586 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1587 arrowp, try, &rval)) 1588 return (0); 1589 if (check_expr_args(&lval, &rval, UINT64, np)) 1590 return (0); 1591 1592 valuep->t = lval.t; 1593 valuep->v = (lval.v | rval.v); 1594 return (1); 1595 1596 case T_BITXOR: 1597 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1598 arrowp, try, &lval)) 1599 return (0); 1600 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1601 arrowp, try, &rval)) 1602 return (0); 1603 if (check_expr_args(&lval, &rval, UINT64, np)) 1604 return (0); 1605 1606 valuep->t = lval.t; 1607 valuep->v = (lval.v ^ rval.v); 1608 return (1); 1609 1610 case T_BITNOT: 1611 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1612 arrowp, try, &lval)) 1613 return (0); 1614 ASSERT(np->u.expr.right == NULL); 1615 if (check_expr_args(&lval, NULL, UINT64, np)) 1616 return (0); 1617 1618 valuep->t = UINT64; 1619 valuep->v = ~ lval.v; 1620 return (1); 1621 1622 case T_LSHIFT: 1623 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1624 arrowp, try, &lval)) 1625 return (0); 1626 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1627 arrowp, try, &rval)) 1628 return (0); 1629 if (check_expr_args(&lval, &rval, UINT64, np)) 1630 return (0); 1631 1632 valuep->t = UINT64; 1633 valuep->v = (lval.v << rval.v); 1634 return (1); 1635 1636 case T_RSHIFT: 1637 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1638 arrowp, try, &lval)) 1639 return (0); 1640 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1641 arrowp, try, &rval)) 1642 return (0); 1643 if (check_expr_args(&lval, &rval, UINT64, np)) 1644 return (0); 1645 1646 valuep->t = UINT64; 1647 valuep->v = (lval.v >> rval.v); 1648 return (1); 1649 1650 case T_CONDIF: { 1651 struct node *retnp; 1652 int dotrue = 0; 1653 1654 /* 1655 * evaluate 1656 * expression ? stmtA [ : stmtB ] 1657 * 1658 * first see if expression is true or false, then determine 1659 * if stmtA (or stmtB, if it exists) should be evaluated. 1660 * 1661 * "dotrue = 1" means stmtA should be evaluated. 1662 */ 1663 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1664 arrowp, try, &lval)) 1665 return (0); 1666 1667 if (lval.t != UNDEFINED && lval.v != 0) 1668 dotrue = 1; 1669 1670 ASSERT(np->u.expr.right != NULL); 1671 if (np->u.expr.right->t == T_CONDELSE) { 1672 if (dotrue) 1673 retnp = np->u.expr.right->u.expr.left; 1674 else 1675 retnp = np->u.expr.right->u.expr.right; 1676 } else { 1677 /* no ELSE clause */ 1678 if (dotrue) 1679 retnp = np->u.expr.right; 1680 else { 1681 outfl(O_DIE, np->file, np->line, 1682 "eval_expr: missing condelse"); 1683 } 1684 } 1685 1686 if (!eval_expr(retnp, ex, events, globals, croot, 1687 arrowp, try, valuep)) 1688 return (0); 1689 return (1); 1690 } 1691 1692 case T_CONDELSE: 1693 /* 1694 * shouldn't get here, since T_CONDELSE is supposed to be 1695 * evaluated as part of T_CONDIF 1696 */ 1697 out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s", 1698 ptree_nodetype2str(np->t)); 1699 /*NOTREACHED*/ 1700 1701 case T_NE: 1702 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1703 arrowp, try, &lval)) 1704 return (0); 1705 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1706 arrowp, try, &rval)) 1707 return (0); 1708 if (rval.t == UINT64 || lval.t == UINT64) { 1709 if (check_expr_args(&lval, &rval, UINT64, np)) 1710 return (0); 1711 } else { 1712 if (check_expr_args(&lval, &rval, UNDEFINED, np)) 1713 return (0); 1714 } 1715 1716 valuep->t = UINT64; 1717 valuep->v = (lval.v != rval.v); 1718 return (1); 1719 1720 case T_LIST: 1721 case T_AND: 1722 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1723 arrowp, try, valuep)) { 1724 /* 1725 * if lhs is unknown, still check rhs. If that 1726 * is false we can return false irrespective of lhs 1727 */ 1728 if (!try) { 1729 np->u.expr.temp = EXPR_TEMP_BOTH_UNK; 1730 return (0); 1731 } 1732 if (!eval_expr(np->u.expr.right, ex, events, globals, 1733 croot, arrowp, try, valuep)) { 1734 np->u.expr.temp = EXPR_TEMP_BOTH_UNK; 1735 return (0); 1736 } 1737 if (valuep->v != 0) { 1738 np->u.expr.temp = EXPR_TEMP_LHS_UNK; 1739 return (0); 1740 } 1741 } 1742 if (valuep->v == 0) { 1743 valuep->t = UINT64; 1744 return (1); 1745 } 1746 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1747 arrowp, try, valuep)) { 1748 np->u.expr.temp = EXPR_TEMP_RHS_UNK; 1749 return (0); 1750 } 1751 valuep->t = UINT64; 1752 valuep->v = valuep->v == 0 ? 0 : 1; 1753 return (1); 1754 1755 case T_OR: 1756 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1757 arrowp, try, valuep)) { 1758 /* 1759 * if lhs is unknown, still check rhs. If that 1760 * is true we can return true irrespective of lhs 1761 */ 1762 if (!try) { 1763 np->u.expr.temp = EXPR_TEMP_BOTH_UNK; 1764 return (0); 1765 } 1766 if (!eval_expr(np->u.expr.right, ex, events, globals, 1767 croot, arrowp, try, valuep)) { 1768 np->u.expr.temp = EXPR_TEMP_BOTH_UNK; 1769 return (0); 1770 } 1771 if (valuep->v == 0) { 1772 np->u.expr.temp = EXPR_TEMP_LHS_UNK; 1773 return (0); 1774 } 1775 } 1776 if (valuep->v != 0) { 1777 valuep->t = UINT64; 1778 valuep->v = 1; 1779 return (1); 1780 } 1781 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1782 arrowp, try, valuep)) { 1783 np->u.expr.temp = EXPR_TEMP_RHS_UNK; 1784 return (0); 1785 } 1786 valuep->t = UINT64; 1787 valuep->v = valuep->v == 0 ? 0 : 1; 1788 return (1); 1789 1790 case T_NOT: 1791 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1792 arrowp, try, valuep)) 1793 return (0); 1794 valuep->t = UINT64; 1795 valuep->v = ! valuep->v; 1796 return (1); 1797 1798 case T_ADD: 1799 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1800 arrowp, try, &lval)) 1801 return (0); 1802 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1803 arrowp, try, &rval)) 1804 return (0); 1805 if (check_expr_args(&lval, &rval, UINT64, np)) 1806 return (0); 1807 1808 valuep->t = lval.t; 1809 valuep->v = lval.v + rval.v; 1810 return (1); 1811 1812 case T_SUB: 1813 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1814 arrowp, try, &lval)) 1815 return (0); 1816 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1817 arrowp, try, &rval)) 1818 return (0); 1819 if (check_expr_args(&lval, &rval, UINT64, np)) 1820 return (0); 1821 1822 /* since valuep is unsigned, return false if lval.v < rval.v */ 1823 if (lval.v < rval.v) { 1824 outfl(O_DIE, np->file, np->line, 1825 "eval_expr: T_SUB result is out of range"); 1826 } 1827 1828 valuep->t = lval.t; 1829 valuep->v = lval.v - rval.v; 1830 return (1); 1831 1832 case T_MUL: 1833 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1834 arrowp, try, &lval)) 1835 return (0); 1836 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1837 arrowp, try, &rval)) 1838 return (0); 1839 if (check_expr_args(&lval, &rval, UINT64, np)) 1840 return (0); 1841 1842 valuep->t = lval.t; 1843 valuep->v = lval.v * rval.v; 1844 return (1); 1845 1846 case T_DIV: 1847 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1848 arrowp, try, &lval)) 1849 return (0); 1850 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1851 arrowp, try, &rval)) 1852 return (0); 1853 if (check_expr_args(&lval, &rval, UINT64, np)) 1854 return (0); 1855 1856 /* return false if dividing by zero */ 1857 if (rval.v == 0) { 1858 outfl(O_DIE, np->file, np->line, 1859 "eval_expr: T_DIV division by zero"); 1860 } 1861 1862 valuep->t = lval.t; 1863 valuep->v = lval.v / rval.v; 1864 return (1); 1865 1866 case T_MOD: 1867 if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1868 arrowp, try, &lval)) 1869 return (0); 1870 if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1871 arrowp, try, &rval)) 1872 return (0); 1873 if (check_expr_args(&lval, &rval, UINT64, np)) 1874 return (0); 1875 1876 /* return false if dividing by zero */ 1877 if (rval.v == 0) { 1878 outfl(O_DIE, np->file, np->line, 1879 "eval_expr: T_MOD division by zero"); 1880 } 1881 1882 valuep->t = lval.t; 1883 valuep->v = lval.v % rval.v; 1884 return (1); 1885 1886 case T_NAME: 1887 if (try) { 1888 struct iterinfo *iterinfop; 1889 struct node *np1, *np2; 1890 int i, gotmatch = 0; 1891 1892 /* 1893 * Check if we have an exact match of the nonwildcarded 1894 * path in oldepname - if so we can just use the 1895 * full wildcarded path in epname. 1896 */ 1897 for (i = 0; i < 1; i++) { 1898 for (np1 = np, 1899 np2 = events[i]->u.event.oldepname; 1900 np1 != NULL && np2 != NULL; 1901 np1 = np1->u.name.next, 1902 np2 = np2->u.name.next) { 1903 if (strcmp(np1->u.name.s, 1904 np2->u.name.s) != 0) 1905 break; 1906 if (np1->u.name.child->t != 1907 np2->u.name.child->t) 1908 break; 1909 if (np1->u.name.child->t == T_NUM && 1910 np1->u.name.child->u.ull != 1911 np2->u.name.child->u.ull) 1912 break; 1913 if (np1->u.name.child->t == T_NAME && 1914 strcmp(np1->u.name.child->u.name.s, 1915 np2->u.name.child->u.name.s) != 0) 1916 break; 1917 gotmatch++; 1918 } 1919 if (np1 == NULL && np2 == NULL) { 1920 valuep->t = NODEPTR; 1921 valuep->v = (uintptr_t) 1922 events[i]->u.event.epname; 1923 return (1); 1924 } 1925 } 1926 if (!gotmatch) { 1927 /* 1928 * we're not wildcarding. However at 1929 * itree_create() time, we can also expand 1930 * simple iterators - so check for those. 1931 */ 1932 iterinfop = lut_lookup(ex, (void *)np->u.name.s, 1933 NULL); 1934 if (iterinfop != NULL) { 1935 valuep->t = UINT64; 1936 valuep->v = 1937 (unsigned long long)iterinfop->num; 1938 return (1); 1939 } 1940 } 1941 /* 1942 * For anything else we'll have to wait for eval_dup(). 1943 */ 1944 return (0); 1945 } 1946 1947 /* return address of struct node */ 1948 valuep->t = NODEPTR; 1949 valuep->v = (uintptr_t)np; 1950 return (1); 1951 1952 case T_QUOTE: 1953 valuep->t = STRING; 1954 valuep->v = (uintptr_t)np->u.quote.s; 1955 return (1); 1956 1957 case T_FUNC: 1958 return (eval_func(np, ex, events, np->u.func.arglist, 1959 globals, croot, arrowp, try, valuep)); 1960 1961 case T_NUM: 1962 case T_TIMEVAL: 1963 valuep->t = UINT64; 1964 valuep->v = np->u.ull; 1965 return (1); 1966 1967 default: 1968 outfl(O_DIE, np->file, np->line, 1969 "eval_expr: unexpected node type: %s", 1970 ptree_nodetype2str(np->t)); 1971 } 1972 /*NOTREACHED*/ 1973 return (0); 1974 } 1975 1976 /* 1977 * eval_fru() and eval_asru() don't do much, but are called from a number 1978 * of places. 1979 */ 1980 static struct node * 1981 eval_fru(struct node *np) 1982 { 1983 ASSERT(np->t == T_NAME); 1984 return (np); 1985 } 1986 1987 static struct node * 1988 eval_asru(struct node *np) 1989 { 1990 ASSERT(np->t == T_NAME); 1991 return (np); 1992 } 1993