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