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