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