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