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.
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.
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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 * eval.c -- constraint evaluation module
28 * this module evaluates constraints.
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
);
57 extern fmd_hdl_t
*Hdl
; /* handle from eft.c */
60 * begins_with -- return true if rhs path begins with everything in lhs path
63 begins_with(struct node
*lhs
, struct node
*rhs
, struct lut
*ex
)
67 struct iterinfo
*iterinfop
;
70 return (1); /* yep -- it all matched */
73 return (0); /* nope, ran out of rhs first */
75 ASSERTeq(lhs
->t
, T_NAME
, ptree_nodetype2str
);
76 ASSERTeq(rhs
->t
, T_NAME
, ptree_nodetype2str
);
78 if (lhs
->u
.name
.s
!= rhs
->u
.name
.s
)
79 return (0); /* nope, different component names */
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
,
86 if (iterinfop
!= NULL
)
87 lnum
= iterinfop
->num
;
89 out(O_DIE
, "begins_with: unexpected lhs child");
91 out(O_DIE
, "begins_with: unexpected lhs child");
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
,
99 if (iterinfop
!= NULL
)
100 rnum
= iterinfop
->num
;
102 out(O_DIE
, "begins_with: unexpected rhs child");
104 out(O_DIE
, "begins_with: unexpected rhs child");
108 return (0); /* nope, instance numbers were different */
110 return (begins_with(lhs
->u
.name
.next
, rhs
->u
.name
.next
, ex
));
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).
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
)
123 const char *funcname
= funcnp
->u
.func
.s
;
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,
136 * Can't evaluate yet. Return null so constraint is
140 if (val
.t
== NODEPTR
)
141 return ((struct node
*)(uintptr_t)val
.v
);
144 * just return the T_FUNC - which the caller will
149 out(O_DIE
, "%s: unexpected type: %s",
150 funcname
, ptree_nodetype2str(np
->t
));
152 if (eval_expr(nodep
, ex
, events
, globals
, croot
,
153 arrowp
, try, &val
) && val
.t
== NODEPTR
)
154 nodep
= (struct node
*)(uintptr_t)val
.v
;
157 nodep
= eval_dup(nodep
, ex
, events
);
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
)
169 if (np
->t
== T_LIST
) {
175 if (!eval_cat(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
178 if (!eval_cat(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
181 len
= snprintf(NULL
, 0, "%s%s", (char *)(uintptr_t)lval
.v
,
182 (char *)(uintptr_t)rval
.v
);
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
);
191 valuep
->v
= (uintptr_t)stable(s
);
194 if (!eval_expr(np
, ex
, events
, globals
, croot
,
195 arrowp
, try, valuep
))
197 if (check_expr_args(valuep
, NULL
, STRING
, np
))
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)
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
)
214 const char *funcname
= funcnp
->u
.func
.s
;
215 int duped_lhs
= 0, duped_rhs
= 0, duped
= 0;
223 if (funcname
== L_within
) {
224 /* within()'s are not really constraints -- always true */
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
);
235 if (rhs
->t
!= T_NAME
|| lhs
->t
!= T_NAME
) {
236 valuep
->t
= UNDEFINED
;
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
);
253 } else if (funcname
== L_confprop
|| funcname
== L_confprop_defined
) {
256 /* for now s will point to a quote [see addconfigprop()] */
257 ASSERT(np
->u
.expr
.right
->t
== T_QUOTE
);
259 nodep
= eval_getname(funcnp
, ex
, events
, np
->u
.expr
.left
,
260 globals
, croot
, arrowp
, try, &duped
);
263 if (nodep
->t
!= T_NAME
) {
264 valuep
->t
= UNDEFINED
;
268 if (nodep
->u
.name
.last
->u
.name
.cp
!= NULL
) {
269 cp
= nodep
->u
.name
.last
->u
.name
.cp
;
271 path
= ipath2str(NULL
, ipath(nodep
));
272 cp
= config_lookup(croot
, path
, 0);
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("");
293 s
= config_getprop(cp
, np
->u
.expr
.right
->u
.quote
.s
);
294 if (s
== NULL
&& strcmp(np
->u
.expr
.right
->u
.quote
.s
,
296 s
= config_getprop(cp
, "CLASS-CODE");
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("");
317 if (funcname
== L_confprop
) {
318 valuep
->v
= (uintptr_t)stable(s
);
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
);
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
;
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
);
346 if (rhs
->t
!= T_NAME
|| lhs
->t
!= T_NAME
) {
347 valuep
->t
= UNDEFINED
;
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
;
356 cp
[0] = config_lookup(croot
, path
, 0);
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
;
363 cp
[1] = config_lookup(croot
, path
, 0);
372 if (cp
[0] == NULL
|| cp
[1] == NULL
)
375 /* to thine self always be connected */
376 if (cp
[0] == cp
[1]) {
382 * Extract "connected" property from each cp. Search this
383 * property for the name associated with the other cp[].
385 for (i
= 0; i
< 2 && valuep
->v
== 0; i
++) {
386 for (j
= 0; connstrings
[j
] != NULL
&& valuep
->v
== 0;
388 s
= config_getprop(cp
[i
],
389 stable(connstrings
[j
]));
391 nameslist
= STRDUP(s
);
392 w
= strtok(nameslist
, " ,");
394 if (stable(w
) == matchthis
[i
]) {
398 w
= strtok(NULL
, " ,");
405 } else if (funcname
== L_is_type
) {
406 const char *typestrings
[] = { "type", "TYPE", NULL
};
410 nodep
= eval_getname(funcnp
, ex
, events
, np
, globals
,
411 croot
, arrowp
, try, &duped
);
414 if (nodep
->t
!= T_NAME
) {
415 valuep
->t
= UNDEFINED
;
419 if (nodep
->u
.name
.last
->u
.name
.cp
!= NULL
) {
420 cp
= nodep
->u
.name
.last
->u
.name
.cp
;
422 path
= ipath2str(NULL
, ipath(nodep
));
423 cp
= config_lookup(croot
, path
, 0);
430 valuep
->v
= (uintptr_t)stable("");
433 for (i
= 0; typestrings
[i
] != NULL
; i
++) {
434 s
= config_getprop(cp
, stable(typestrings
[i
]));
436 valuep
->v
= (uintptr_t)stable(s
);
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
};
448 nodep
= eval_getname(funcnp
, ex
, events
, np
, globals
,
449 croot
, arrowp
, try, &duped
);
452 if (nodep
->t
!= T_NAME
) {
453 valuep
->t
= UNDEFINED
;
457 if (nodep
->u
.name
.last
->u
.name
.cp
!= NULL
) {
458 cp
= nodep
->u
.name
.last
->u
.name
.cp
;
460 path
= ipath2str(NULL
, ipath(nodep
));
461 cp
= config_lookup(croot
, path
, 0);
471 for (i
= 0; onstrings
[i
] != NULL
; i
++) {
472 s
= config_getprop(cp
, stable(onstrings
[i
]));
475 for (j
= 0; truestrings
[j
] != NULL
; j
++) {
476 if (s
== stable(truestrings
[j
])) {
484 } else if (funcname
== L_is_present
) {
485 nodep
= eval_getname(funcnp
, ex
, events
, np
, globals
,
486 croot
, arrowp
, try, &duped
);
489 if (nodep
->t
!= T_NAME
) {
490 valuep
->t
= UNDEFINED
;
494 if (nodep
->u
.name
.last
->u
.name
.cp
!= NULL
) {
495 cp
= nodep
->u
.name
.last
->u
.name
.cp
;
497 path
= ipath2str(NULL
, ipath(nodep
));
498 cp
= config_lookup(croot
, path
, 0);
509 } else if (funcname
== L_has_fault
) {
510 nvlist_t
*asru
= NULL
, *fru
= NULL
, *rsrc
= NULL
;
512 nodep
= eval_getname(funcnp
, ex
, events
, np
->u
.expr
.left
,
513 globals
, croot
, arrowp
, try, &duped
);
516 if (nodep
->t
!= T_NAME
) {
517 valuep
->t
= UNDEFINED
;
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
);
533 out(O_ALTFP
|O_VERB2
, "no path");
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
);
544 } else if (funcname
== L_count
) {
546 struct istat_entry ent
;
548 ASSERTinfo(np
->t
== T_EVENT
, ptree_nodetype2str(np
->t
));
550 nodep
= np
->u
.event
.epname
;
552 if (eval_expr(nodep
, ex
, events
, globals
,
553 croot
, arrowp
, try, &val
) && val
.t
== NODEPTR
)
554 nodep
= (struct node
*)(uintptr_t)val
.v
;
557 nodep
= eval_dup(nodep
, ex
, events
);
560 ent
.ename
= np
->u
.event
.ename
->u
.name
.s
;
561 ent
.ipath
= ipath(nodep
);
563 if ((statp
= (struct stats
*)
564 lut_lookup(Istats
, &ent
, (lut_cmp
)istat_cmp
)) == NULL
)
567 valuep
->v
= stats_counter_value(statp
);
571 } else if (funcname
== L_envprop
) {
572 outfl(O_DIE
, np
->file
, np
->line
,
573 "eval_func: %s not yet supported", funcname
);
579 if (funcname
== L_fru
) {
581 valuep
->v
= (uintptr_t)eval_fru(np
);
583 } else if (funcname
== L_asru
) {
585 valuep
->v
= (uintptr_t)eval_asru(np
);
587 } else if (funcname
== L_defined
) {
588 ASSERTeq(np
->t
, T_GLOBID
, ptree_nodetype2str
);
590 valuep
->v
= (lut_lookup(*globals
,
591 (void *)np
->u
.globid
.s
, NULL
) != NULL
);
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
);
599 if (arrowp
->head
->myevent
->count
== 0) {
601 * Haven't seen this ereport yet, so must defer
603 out(O_ALTFP
|O_VERB2
, "ereport not yet seen - defer.");
605 } else if (platform_payloadprop(np
, valuep
)) {
606 /* platform_payloadprop() returned false */
607 out(O_ALTFP
|O_VERB
, "not found.");
608 valuep
->t
= UNDEFINED
;
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
));
622 out(O_ALTFP
|O_VERB2
, "found: %llu",
626 out(O_ALTFP
|O_VERB2
, "found: %llu", valuep
->v
);
629 out(O_ALTFP
|O_VERB2
, "found: \"%s\"",
630 (char *)(uintptr_t)valuep
->v
);
633 out(O_ALTFP
|O_VERB2
, "found: undefined");
638 } else if (funcname
== L_setpayloadprop
) {
639 struct evalue
*payloadvalp
;
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
));
646 if (!(arrowp
->head
->myevent
->cached_state
& REQMNTS_CREDIBLE
))
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
);
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.
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
));
668 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
669 arrowp
, try, payloadvalp
)) {
670 out(O_ALTFP
|O_VERB2
, " (cannot eval)");
675 if (payloadvalp
->t
== UNDEFINED
) {
676 /* function is always true */
677 out(O_ALTFP
|O_VERB2
, " (undefined)");
682 if (payloadvalp
->t
== UINT64
)
684 " (%llu)", payloadvalp
->v
);
686 out(O_ALTFP
|O_VERB2
, " (\"%s\")",
687 (char *)(uintptr_t)payloadvalp
->v
);
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
);
696 /* function is always true */
700 } else if (funcname
== L_cat
) {
701 int retval
= eval_cat(np
, ex
, events
, globals
, croot
,
702 arrowp
, try, valuep
);
704 outfl(O_ALTFP
|O_VERB2
, np
->file
, np
->line
,
705 "cat: returns %s", (char *)(uintptr_t)valuep
->v
);
707 } else if (funcname
== L_setserdn
|| funcname
== L_setserdt
||
708 funcname
== L_setserdsuffix
|| funcname
== L_setserdincrement
) {
709 struct evalue
*serdvalp
;
712 struct event
*flt
= arrowp
->tail
->myevent
;
714 if (!(arrowp
->head
->myevent
->cached_state
& REQMNTS_CREDIBLE
))
717 if (funcname
== L_setserdn
)
719 else if (funcname
== L_setserdt
)
721 else if (funcname
== L_setserdsuffix
)
723 else if (funcname
== L_setserdincrement
)
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.
732 if ((serdvalp
= (struct evalue
*)lut_lookup(flt
->serdprops
,
733 (void *)str
, (lut_cmp
)strcmp
)) == NULL
) {
734 serdvalp
= MALLOC(sizeof (*serdvalp
));
738 if (!eval_expr(np
, ex
, events
, globals
, croot
, arrowp
, try,
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)");
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)");
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);
765 if (funcname
== L_setserdt
&& serdvalp
->t
== UINT64
) {
766 int len
= snprintf(NULL
, 0, "%lldns",
768 char *buf
= MALLOC(len
+ 1);
770 (void) snprintf(buf
, len
+ 1, "%lldns",
772 serdvalp
->t
= STRING
;
773 serdvalp
->v
= (uintptr_t)stable(buf
);
776 if (funcname
== L_setserdsuffix
&&
777 serdvalp
->t
== UINT64
) {
778 int len
= snprintf(NULL
, 0, "%lld",
780 char *buf
= MALLOC(len
+ 1);
782 (void) snprintf(buf
, len
+ 1, "%lld",
784 serdvalp
->t
= STRING
;
785 serdvalp
->v
= (uintptr_t)stable(buf
);
789 if (serdvalp
->t
== UINT64
)
790 out(O_ALTFP
|O_VERB2
, " (%llu)", serdvalp
->v
);
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
);
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
);
804 if (arrowp
->head
->myevent
->count
== 0) {
806 * Haven't seen this ereport yet, so must defer
808 out(O_ALTFP
|O_VERB2
, "ereport not yet seen - defer.");
810 } else if (platform_payloadprop(np
, NULL
)) {
811 /* platform_payloadprop() returned false */
813 out(O_ALTFP
|O_VERB2
, "not found.");
816 out(O_ALTFP
|O_VERB2
, "found.");
820 } else if (funcname
== L_payloadprop_contains
) {
823 struct evalue cmpval
;
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
));
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
, ") ");
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
,
844 out(O_ALTFP
|O_VERB2
, "(undefined type)");
849 "(%llu) ", cmpval
.v
);
854 "(\"%s\") ", (char *)(uintptr_t)cmpval
.v
);
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
, ") ");
866 /* get the payload values and check for a match */
867 vals
= platform_payloadprop_values(np
->u
.expr
.left
->u
.quote
.s
,
871 if (arrowp
->head
->myevent
->count
== 0) {
873 * Haven't seen this ereport yet, so must defer
875 out(O_ALTFP
|O_VERB2
, "ereport not yet seen - defer.");
877 } else if (nvals
== 0) {
878 out(O_ALTFP
|O_VERB2
, "not found.");
881 struct evalue preval
;
884 out(O_ALTFP
|O_VERB2
|O_NONL
, "found %d values ", nvals
);
886 for (i
= 0; i
< nvals
; i
++) {
888 preval
.t
= vals
[i
].t
;
889 preval
.v
= vals
[i
].v
;
891 if (check_expr_args(&vals
[i
], &cmpval
,
896 * If we auto-converted the value to a
897 * string, we need to free the
898 * original tree value.
900 if (preval
.t
== NODEPTR
&&
901 ((struct node
*)(uintptr_t)(preval
.v
))->t
==
903 tree_free((struct node
*)(uintptr_t)
907 if (vals
[i
].v
== cmpval
.v
) {
914 out(O_ALTFP
|O_VERB2
, "match.");
916 out(O_ALTFP
|O_VERB2
, "no match.");
918 for (i
= 0; i
< nvals
; i
++) {
919 if (vals
[i
].t
== NODEPTR
) {
920 tree_free((struct node
*)(uintptr_t)
928 } else if (funcname
== L_confcall
) {
929 return (!platform_confcall(np
, globals
, croot
, arrowp
, valuep
));
931 outfl(O_DIE
, np
->file
, np
->line
,
932 "eval_func: unexpected func: %s", funcname
);
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.
943 #define EXPR_TEMP_BOTH_UNK 0
944 #define EXPR_TEMP_LHS_UNK 1
945 #define EXPR_TEMP_RHS_UNK 2
948 eval_dup(struct node
*np
, struct lut
*ex
, struct node
*events
[])
957 return (tree_globid(np
->u
.globid
.s
, np
->file
, np
->line
));
980 return (tree_expr(np
->t
,
981 eval_dup(np
->u
.expr
.left
, ex
, events
),
982 eval_dup(np
->u
.expr
.right
, ex
, events
)));
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
));
991 return (tree_expr(np
->t
,
992 eval_dup(np
->u
.expr
.left
, ex
, events
),
993 eval_dup(np
->u
.expr
.right
, ex
, events
)));
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
));
1003 return (tree_expr(T_OR
,
1004 eval_dup(np
->u
.expr
.left
, ex
, events
),
1005 eval_dup(np
->u
.expr
.right
, ex
, events
)));
1009 struct iterinfo
*iterinfop
;
1012 struct evalue value
;
1013 struct node
*np1f
, *np2f
, *np1t
, *np2t
, *retp
= NULL
;
1014 struct node
*npstart
, *npcont
, *npend
, *npref
, *newnp
, *nprest
;
1017 * Check if we already have a match of the nonwildcarded path
1018 * in oldepname (check both to and from events).
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)
1025 if (np1f
->u
.name
.child
->t
!= np2f
->u
.name
.child
->t
)
1027 if (np1f
->u
.name
.child
->t
== T_NUM
&&
1028 np1f
->u
.name
.child
->u
.ull
!=
1029 np2f
->u
.name
.child
->u
.ull
)
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)
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)
1042 if (np1t
->u
.name
.child
->t
!= np2t
->u
.name
.child
->t
)
1044 if (np1t
->u
.name
.child
->t
== T_NUM
&&
1045 np1t
->u
.name
.child
->u
.ull
!=
1046 np2t
->u
.name
.child
->u
.ull
)
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)
1055 if (got_matchf
|| got_matcht
) {
1057 * so we are wildcarding. Copy ewname in full, plus
1058 * matching section of oldepname. Use whichever gives
1059 * the closest match.
1061 if (got_matchf
> got_matcht
) {
1062 npstart
= events
[0]->u
.event
.ewname
;
1063 npcont
= events
[0]->u
.event
.oldepname
;
1067 npstart
= events
[1]->u
.event
.ewname
;
1068 npcont
= events
[1]->u
.event
.oldepname
;
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
);
1089 newnp
->u
.name
.child
->u
.ull
= value
.v
;
1093 retp
->u
.name
.last
->u
.name
.next
= newnp
;
1094 retp
->u
.name
.last
= newnp
;
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
);
1114 newnp
->u
.name
.child
->u
.ull
= value
.v
;
1118 retp
->u
.name
.last
->u
.name
.next
= newnp
;
1119 retp
->u
.name
.last
= newnp
;
1124 * not wildcarding - check if explicit iterator
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
;
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).
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
);
1157 newnp
->u
.name
.child
->u
.ull
= value
.v
;
1161 retp
->u
.name
.last
->u
.name
.next
= newnp
;
1162 retp
->u
.name
.last
= newnp
;
1169 newnp
= newnode(T_NAME
, np
->file
, np
->line
);
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
;
1176 return (tree_event(newnp
,
1177 eval_dup(np
->u
.event
.epname
, ex
, events
),
1178 eval_dup(np
->u
.event
.eexprlist
, ex
, events
)));
1181 return (tree_func(np
->u
.func
.s
,
1182 eval_dup(np
->u
.func
.arglist
, ex
, events
),
1183 np
->file
, np
->line
));
1186 newnp
= newnode(T_QUOTE
, np
->file
, np
->line
);
1187 newnp
->u
.quote
.s
= np
->u
.quote
.s
;
1191 newnp
= newnode(T_NUM
, np
->file
, np
->line
);
1192 newnp
->u
.ull
= np
->u
.ull
;
1196 newnp
= newnode(T_TIMEVAL
, np
->file
, np
->line
);
1197 newnp
->u
.ull
= np
->u
.ull
;
1201 outfl(O_DIE
, np
->file
, np
->line
,
1202 "eval_dup: unexpected node type: %s",
1203 ptree_nodetype2str(np
->t
));
1210 * eval_potential -- see if constraint is potentially true
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.
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.
1228 * return of false: constraint can never be true, *newc will be NULL.
1230 * return of true with *newc unchanged: constraint will always be true.
1232 * return of true with *newc changed: use new constraint in *newc.
1234 * the lookup table for all explicit iterators, ex, is passed in.
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.
1243 eval_potential(struct node
*np
, struct lut
*ex
, struct node
*events
[],
1244 struct node
**newc
, struct config
*croot
)
1247 struct evalue value
;
1249 if (eval_expr(np
, ex
, events
, NULL
, croot
, NULL
, 1, &value
) == 0) {
1251 * couldn't eval expression because
1252 * it contains deferred items. make
1253 * a duplicate expression with all the
1254 * non-deferred items expanded.
1256 newnp
= eval_dup(np
, ex
, events
);
1258 if (*newc
== NULL
) {
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.
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.
1273 *newc
= tree_expr(T_AND
, *newc
, newnp
);
1276 } else if (value
.t
== UNDEFINED
) {
1277 /* constraint can never be true */
1279 } else if (value
.t
== UINT64
&& value
.v
== 0) {
1280 /* constraint can never be true */
1283 /* constraint is always true (nothing deferred to eval) */
1289 check_expr_args(struct evalue
*lp
, struct evalue
*rp
, enum datatype dtype
,
1292 /* auto-convert T_NAMES to strings */
1293 if (lp
->t
== NODEPTR
&& ((struct node
*)(uintptr_t)(lp
->v
))->t
==
1295 char *s
= ipath2str(NULL
,
1296 ipath((struct node
*)(uintptr_t)lp
->v
));
1298 lp
->v
= (uintptr_t)stable(s
);
1300 out(O_ALTFP
|O_VERB2
, "convert lhs path to \"%s\"",
1301 (char *)(uintptr_t)lp
->v
);
1304 rp
->t
== NODEPTR
&& ((struct node
*)(uintptr_t)(rp
->v
))->t
==
1306 char *s
= ipath2str(NULL
,
1307 ipath((struct node
*)(uintptr_t)rp
->v
));
1309 rp
->v
= (uintptr_t)stable(s
);
1311 out(O_ALTFP
|O_VERB2
, "convert rhs path to \"%s\"",
1312 (char *)(uintptr_t)rp
->v
);
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);
1321 (void) snprintf(s
, len
+ 1, "%llx", lp
->v
);
1323 lp
->v
= (uintptr_t)stable(s
);
1326 if (rp
!= NULL
&& rp
->t
== UINT64
) {
1327 int len
= snprintf(NULL
, 0, "%llx", rp
->v
);
1328 char *s
= MALLOC(len
+ 1);
1330 (void) snprintf(s
, len
+ 1, "%llx", rp
->v
);
1332 rp
->v
= (uintptr_t)stable(s
);
1337 /* auto-convert strings to numbers */
1338 if (dtype
== UINT64
) {
1339 if (lp
->t
== STRING
) {
1341 lp
->v
= strtoull((char *)(uintptr_t)lp
->v
, NULL
, 0);
1343 if (rp
!= NULL
&& rp
->t
== STRING
) {
1345 rp
->v
= strtoull((char *)(uintptr_t)rp
->v
, NULL
, 0);
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
));
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
));
1369 * eval_expr -- evaluate expression into *valuep
1371 * the meaning of the return value depends on the input value of try.
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.
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)
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
)
1389 struct evalue
*gval
;
1395 valuep
->v
= 1; /* no constraint means "true" */
1399 valuep
->t
= UNDEFINED
;
1407 * only handle case of getting (and not setting) the value
1408 * of a global variable
1410 gval
= lut_lookup(*globals
, (void *)np
->u
.globid
.s
, NULL
);
1414 valuep
->t
= gval
->t
;
1415 valuep
->v
= gval
->v
;
1424 * first evaluate rhs, then try to store value in lhs which
1425 * should be a global variable
1427 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1428 arrowp
, try, &rval
))
1431 ASSERT(np
->u
.expr
.left
->t
== T_GLOBID
);
1432 gval
= lut_lookup(*globals
,
1433 (void *)np
->u
.expr
.left
->u
.globid
.s
, NULL
);
1436 gval
= MALLOC(sizeof (*gval
));
1437 *globals
= lut_add(*globals
,
1438 (void *) np
->u
.expr
.left
->u
.globid
.s
, gval
, NULL
);
1444 if (gval
->t
== UINT64
) {
1445 out(O_ALTFP
|O_VERB2
,
1447 np
->u
.expr
.left
->u
.globid
.s
, gval
->v
);
1449 out(O_ALTFP
|O_VERB2
,
1450 "assign $%s=\"%s\"",
1451 np
->u
.expr
.left
->u
.globid
.s
,
1452 (char *)(uintptr_t)gval
->v
);
1456 * but always return true -- an assignment should not
1457 * cause a constraint to be false.
1464 #define IMPLICIT_ASSIGN_IN_EQ
1465 #ifdef IMPLICIT_ASSIGN_IN_EQ
1467 * if lhs is an uninitialized global variable, perform
1470 * one insidious side effect of implicit assignment is
1471 * that the "==" operator does not return a Boolean if
1472 * implicit assignment was performed.
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
))
1482 gval
= MALLOC(sizeof (*gval
));
1483 *globals
= lut_add(*globals
,
1484 (void *) np
->u
.expr
.left
->u
.globid
.s
,
1493 #endif /* IMPLICIT_ASSIGN_IN_EQ */
1495 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1496 arrowp
, try, &lval
))
1498 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1499 arrowp
, try, &rval
))
1501 if (rval
.t
== UINT64
|| lval
.t
== UINT64
) {
1502 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1505 if (check_expr_args(&lval
, &rval
, UNDEFINED
, np
))
1510 valuep
->v
= (lval
.v
== rval
.v
);
1514 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1515 arrowp
, try, &lval
))
1517 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1518 arrowp
, try, &rval
))
1520 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1524 valuep
->v
= (lval
.v
< rval
.v
);
1528 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1529 arrowp
, try, &lval
))
1531 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1532 arrowp
, try, &rval
))
1534 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1538 valuep
->v
= (lval
.v
<= rval
.v
);
1542 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1543 arrowp
, try, &lval
))
1545 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1546 arrowp
, try, &rval
))
1548 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1552 valuep
->v
= (lval
.v
> rval
.v
);
1556 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1557 arrowp
, try, &lval
))
1559 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1560 arrowp
, try, &rval
))
1562 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1566 valuep
->v
= (lval
.v
>= rval
.v
);
1570 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1571 arrowp
, try, &lval
))
1573 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1574 arrowp
, try, &rval
))
1576 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1580 valuep
->v
= (lval
.v
& rval
.v
);
1584 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1585 arrowp
, try, &lval
))
1587 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1588 arrowp
, try, &rval
))
1590 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1594 valuep
->v
= (lval
.v
| rval
.v
);
1598 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1599 arrowp
, try, &lval
))
1601 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1602 arrowp
, try, &rval
))
1604 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1608 valuep
->v
= (lval
.v
^ rval
.v
);
1612 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1613 arrowp
, try, &lval
))
1615 ASSERT(np
->u
.expr
.right
== NULL
);
1616 if (check_expr_args(&lval
, NULL
, UINT64
, np
))
1620 valuep
->v
= ~ lval
.v
;
1624 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1625 arrowp
, try, &lval
))
1627 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1628 arrowp
, try, &rval
))
1630 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1634 valuep
->v
= (lval
.v
<< rval
.v
);
1638 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1639 arrowp
, try, &lval
))
1641 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1642 arrowp
, try, &rval
))
1644 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1648 valuep
->v
= (lval
.v
>> rval
.v
);
1657 * expression ? stmtA [ : stmtB ]
1659 * first see if expression is true or false, then determine
1660 * if stmtA (or stmtB, if it exists) should be evaluated.
1662 * "dotrue = 1" means stmtA should be evaluated.
1664 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1665 arrowp
, try, &lval
))
1668 if (lval
.t
!= UNDEFINED
&& lval
.v
!= 0)
1671 ASSERT(np
->u
.expr
.right
!= NULL
);
1672 if (np
->u
.expr
.right
->t
== T_CONDELSE
) {
1674 retnp
= np
->u
.expr
.right
->u
.expr
.left
;
1676 retnp
= np
->u
.expr
.right
->u
.expr
.right
;
1678 /* no ELSE clause */
1680 retnp
= np
->u
.expr
.right
;
1682 outfl(O_DIE
, np
->file
, np
->line
,
1683 "eval_expr: missing condelse");
1687 if (!eval_expr(retnp
, ex
, events
, globals
, croot
,
1688 arrowp
, try, valuep
))
1695 * shouldn't get here, since T_CONDELSE is supposed to be
1696 * evaluated as part of T_CONDIF
1698 out(O_ALTFP
|O_DIE
, "eval_expr: wrong context for operation %s",
1699 ptree_nodetype2str(np
->t
));
1703 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1704 arrowp
, try, &lval
))
1706 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1707 arrowp
, try, &rval
))
1709 if (rval
.t
== UINT64
|| lval
.t
== UINT64
) {
1710 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1713 if (check_expr_args(&lval
, &rval
, UNDEFINED
, np
))
1718 valuep
->v
= (lval
.v
!= rval
.v
);
1723 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1724 arrowp
, try, valuep
)) {
1726 * if lhs is unknown, still check rhs. If that
1727 * is false we can return false irrespective of lhs
1730 np
->u
.expr
.temp
= EXPR_TEMP_BOTH_UNK
;
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
;
1738 if (valuep
->v
!= 0) {
1739 np
->u
.expr
.temp
= EXPR_TEMP_LHS_UNK
;
1743 if (valuep
->v
== 0) {
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
;
1753 valuep
->v
= valuep
->v
== 0 ? 0 : 1;
1757 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1758 arrowp
, try, valuep
)) {
1760 * if lhs is unknown, still check rhs. If that
1761 * is true we can return true irrespective of lhs
1764 np
->u
.expr
.temp
= EXPR_TEMP_BOTH_UNK
;
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
;
1772 if (valuep
->v
== 0) {
1773 np
->u
.expr
.temp
= EXPR_TEMP_LHS_UNK
;
1777 if (valuep
->v
!= 0) {
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
;
1788 valuep
->v
= valuep
->v
== 0 ? 0 : 1;
1792 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1793 arrowp
, try, valuep
))
1796 valuep
->v
= ! valuep
->v
;
1800 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1801 arrowp
, try, &lval
))
1803 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1804 arrowp
, try, &rval
))
1806 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1810 valuep
->v
= lval
.v
+ rval
.v
;
1814 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1815 arrowp
, try, &lval
))
1817 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1818 arrowp
, try, &rval
))
1820 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
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");
1830 valuep
->v
= lval
.v
- rval
.v
;
1834 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1835 arrowp
, try, &lval
))
1837 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1838 arrowp
, try, &rval
))
1840 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1844 valuep
->v
= lval
.v
* rval
.v
;
1848 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1849 arrowp
, try, &lval
))
1851 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1852 arrowp
, try, &rval
))
1854 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1857 /* return false if dividing by zero */
1859 outfl(O_DIE
, np
->file
, np
->line
,
1860 "eval_expr: T_DIV division by zero");
1864 valuep
->v
= lval
.v
/ rval
.v
;
1868 if (!eval_expr(np
->u
.expr
.left
, ex
, events
, globals
, croot
,
1869 arrowp
, try, &lval
))
1871 if (!eval_expr(np
->u
.expr
.right
, ex
, events
, globals
, croot
,
1872 arrowp
, try, &rval
))
1874 if (check_expr_args(&lval
, &rval
, UINT64
, np
))
1877 /* return false if dividing by zero */
1879 outfl(O_DIE
, np
->file
, np
->line
,
1880 "eval_expr: T_MOD division by zero");
1884 valuep
->v
= lval
.v
% rval
.v
;
1889 struct iterinfo
*iterinfop
;
1890 struct node
*np1
, *np2
;
1891 int i
, gotmatch
= 0;
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.
1898 for (i
= 0; i
< 1; i
++) {
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)
1907 if (np1
->u
.name
.child
->t
!=
1908 np2
->u
.name
.child
->t
)
1910 if (np1
->u
.name
.child
->t
== T_NUM
&&
1911 np1
->u
.name
.child
->u
.ull
!=
1912 np2
->u
.name
.child
->u
.ull
)
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)
1920 if (np1
== NULL
&& np2
== NULL
) {
1921 valuep
->t
= NODEPTR
;
1922 valuep
->v
= (uintptr_t)
1923 events
[i
]->u
.event
.epname
;
1929 * we're not wildcarding. However at
1930 * itree_create() time, we can also expand
1931 * simple iterators - so check for those.
1933 iterinfop
= lut_lookup(ex
, (void *)np
->u
.name
.s
,
1935 if (iterinfop
!= NULL
) {
1938 (unsigned long long)iterinfop
->num
;
1943 * For anything else we'll have to wait for eval_dup().
1948 /* return address of struct node */
1949 valuep
->t
= NODEPTR
;
1950 valuep
->v
= (uintptr_t)np
;
1955 valuep
->v
= (uintptr_t)np
->u
.quote
.s
;
1959 return (eval_func(np
, ex
, events
, np
->u
.func
.arglist
,
1960 globals
, croot
, arrowp
, try, valuep
));
1965 valuep
->v
= np
->u
.ull
;
1969 outfl(O_DIE
, np
->file
, np
->line
,
1970 "eval_expr: unexpected node type: %s",
1971 ptree_nodetype2str(np
->t
));
1978 * eval_fru() and eval_asru() don't do much, but are called from a number
1981 static struct node
*
1982 eval_fru(struct node
*np
)
1984 ASSERT(np
->t
== T_NAME
);
1988 static struct node
*
1989 eval_asru(struct node
*np
)
1991 ASSERT(np
->t
== T_NAME
);