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