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