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