check.c revision 754564661a990e58301b3840826dab55b72c2963
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* check.c -- routines for checking the prop tree
*
* this module provides semantic checks on the parse tree. most of
* these checks happen during the construction of the parse tree,
* when the various tree_X() routines call the various check_X()
* routines. in a couple of special cases, a check function will
* process the parse tree after it has been fully constructed. these
* cases are noted in the comments above the check function.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include "out.h"
#include "stable.h"
#include "literals.h"
#include "lut.h"
#include "tree.h"
#include "ptree.h"
#include "check.h"
static struct {
enum nodetype t;
const char *name;
int required;
int outflags;
} Allowednames[] = {
{ 0, NULL, 0 },
};
void
check_init(void)
{
int i;
for (i = 0; Allowednames[i].t; i++)
}
void
check_fini(void)
{
}
/*ARGSUSED*/
void
{
/* nothing to check for here. poller is only prop and it is optional */
}
/*
* check_path_iterators -- verify all iterators are explicit
*/
static void
{
return;
switch (np->t) {
case T_ARROW:
break;
case T_LIST:
break;
case T_EVENT:
break;
case T_NAME:
"internal error: check_path_iterators: "
"unexpected implicit iterator: %s",
break;
default:
"internal error: check_path_iterators: "
"unexpected type: %s",
ptree_nodetype2str(np->t));
}
}
void
{
"%s not allowed on left-hand side of arrow",
}
"counts associated with propagation arrows "
"must be integers");
}
/*
* make sure the nork values are valid.
* Nork values must be "A" for all(T_NAME),
* a number(T_NUM), or a simple
* expression(T_SUB, T_ADD, T_MUL, T_DIV)
*/
static int
{
int rval = 0;
/* NULL means no nork value which is allowed */
rval = 1;
}
else
{
/* if the nork is a name it must be A for "All" */
return (1);
/* T_NUM allowed */
rval = 1;
/* simple expressions allowed */
rval = 1;
}
return (rval);
}
static int
{
return (1);
"%s %s property must begin with \"ereport.\"",
ptree_nodetype2str(t), s);
"%s %s property contains undeclared name",
ptree_nodetype2str(t), s);
}
}
return (1);
}
static int
{
"%s %s property must be a single number",
ptree_nodetype2str(t), s);
return (1);
}
/*ARGSUSED1*/
static int
{
"%s properties must be quoted strings",
ptree_nodetype2str(t));
return (1);
}
static int
{
"%s %s property must be a number or function",
ptree_nodetype2str(t), s);
return (1);
}
static int
{
/* make sure it is a node type T_NAME? */
if (s == L_ASRU) {
"ASRU property contains undeclared asru");
} else if (s == L_FRU) {
"FRU property contains undeclared fru");
} else {
"illegal property name in %s declaration: %s",
ptree_nodetype2str(t), s);
}
} else
"illegal type used for %s property: %s",
s, ptree_nodetype2str(np->t));
return (1);
}
static int
{
"%s %s property must be an engine name "
"(i.e. serd.x or serd.x@a/b)",
ptree_nodetype2str(t), s);
return (1);
}
static int
{
"%s %s property must be a number with time units",
ptree_nodetype2str(t), s);
return (1);
}
static int
{
"%s %s property must be simple name",
ptree_nodetype2str(t), s);
return (1);
}
static int
{
"%s %s property must be \"volatile\" or \"persistent\"",
ptree_nodetype2str(t), s);
return (1);
}
void
{
int i;
for (i = 0; Allowednames[i].t; i++)
if (stmtnp->t == Allowednames[i].t &&
Allowednames[i].required &&
"%s statement missing property: %s",
ptree_nodetype2str(stmtnp->t),
Allowednames[i].name);
}
void
{
int i;
for (i = 0; Allowednames[i].t; i++)
/* NULL name means just call checker */
(*Allowednames[i].checker)(t, s,
return;
break;
"illegal property name in %s declaration: %s",
ptree_nodetype2str(t), s);
/*
* redeclaring prop is allowed if value is the same
*/
"property redeclared (with differnt type) "
"in %s declaration: %s",
ptree_nodetype2str(t), s);
switch (np->t) {
case T_NUM:
case T_TIMEVAL:
return;
break;
case T_NAME:
if (tree_namecmp(np,
return;
break;
case T_EVENT:
if (tree_eventcmp(np,
return;
break;
default:
"value for property \"%s\" is an "
"invalid type: %s",
ptree_nodetype2str(np->t));
return;
}
"property redeclared in %s declaration: %s",
ptree_nodetype2str(t), s);
} else
}
void
{
ptree_nodetype2str(np->t));
case N_UNSPEC:
"name in %s statement must begin with "
"type (example: \"error.\")",
ptree_nodetype2str(t));
return;
case N_FAULT:
if (to) {
"%s has fault on right side of \"->\"",
ptree_nodetype2str(t));
return;
}
if (!from) {
"internal error: %s has fault without "
"from flag",
ptree_nodetype2str(t));
}
break;
case N_UPSET:
if (to) {
"%s has upset on right side of \"->\"",
ptree_nodetype2str(t));
return;
}
if (!from)
"internal error: %s has upset without "
"from flag",
ptree_nodetype2str(t));
break;
case N_DEFECT:
if (to) {
"%s has defect on right side of \"->\"",
ptree_nodetype2str(t));
return;
}
if (!from) {
"internal error: %s has defect without "
"from flag",
ptree_nodetype2str(t));
}
break;
case N_ERROR:
"%s has error without from or to flags",
ptree_nodetype2str(t));
break;
case N_EREPORT:
if (from) {
"%s has report on left side of \"->\"",
ptree_nodetype2str(t));
return;
}
if (!to)
"internal error: %s has report without "
"to flag",
ptree_nodetype2str(t));
break;
default:
"internal error: check_propnames: "
}
"%s statement contains undeclared event",
ptree_nodetype2str(t));
} else
}
}
static struct lut *
{
return (ex);
switch (np->t) {
case T_ARROW:
break;
case T_LIST:
break;
case T_EVENT:
break;
case T_NAME:
break;
default:
"record_iterators: internal error: unexpected type: %s",
ptree_nodetype2str(np->t));
}
return (ex);
}
void
{
return;
switch (np->t) {
case T_EVENT:
break;
case T_ARROW:
break;
case T_NAME:
if (lut_lookup(ex,
"constraint contains undefined"
" iterator: %s",
}
break;
case T_QUOTE:
case T_GLOBID:
break;
case T_ASSIGN:
case T_NE:
case T_EQ:
case T_LIST:
case T_AND:
case T_OR:
case T_NOT:
case T_ADD:
case T_SUB:
case T_MUL:
case T_DIV:
case T_MOD:
case T_LT:
case T_LE:
case T_GT:
case T_GE:
case T_BITAND:
case T_BITOR:
case T_BITXOR:
case T_BITNOT:
case T_LSHIFT:
case T_RSHIFT:
case T_CONDIF:
case T_CONDELSE:
break;
case T_FUNC:
break;
case T_NUM:
case T_TIMEVAL:
break;
default:
"check_exprscope: internal error: unexpected type: %s",
ptree_nodetype2str(np->t));
}
}
/*
* check_propscope -- check constraints for out of scope variable refs
*/
void
{
}
/*
* check_upset_engine -- validate the engine property in an upset statement
*
* we do this after the full parse tree has been constructed rather than while
* building the parse tree because it is inconvenient for the user if we
* require SERD engines to be declared before used in an upset "engine"
* property.
*/
/*ARGSUSED*/
void
{
return;
"%s %s property contains undeclared name",
ptree_nodetype2str(t), L_engine);
return;
}
}
/*
* check_refcount -- see if declared names are used
*
* this is run after the entire parse tree is constructed, so a refcount
* of zero means the name has been declared but otherwise not used.
*/
void
{
return;
"%s name declared but not used: ", ptree_nodetype2str(t));
}
/*
* set check_cycle_warninglevel only for val >= 0
*/
int
check_cycle_level(long long val)
{
static int check_cycle_warninglevel = -1;
if (val == 0)
else if (val > 0)
return (check_cycle_warninglevel);
}
/*
* check_cycle -- see props from an error have cycles
*
* this is run after the entire parse tree is constructed, for
* each error that has been declared.
*/
/*ARGSUSED*/
void
{
return; /* already reported this cycle */
#ifdef ESC
int warninglevel;
if (warninglevel <= 0) {
if (warninglevel == 0)
}
#endif /* ESC */
}
/* for each propagation */
}
/*
* check_cycle_lhs -- find the lhs of an arrow for cycle checking
*/
static void
{
/* handle cascaded arrows */
case T_ARROW:
/* first recurse left */
/* then try this arrow (thing cascaded *to*) */
break;
case T_EVENT:
case T_LIST:
break;
default:
/*NOTREACHED*/
}
}
/*
* check_cycle_lhs_try -- try matching an event name on lhs of an arrow
*/
static void
{
return;
}
return; /* no match */
}
/*
* check_cycle_rhs -- foreach error on rhs, see if we cycle to a marked error
*/
static void
{
return;
}
return;
"unexpected undeclared event during cycle check");
return;
}
}
/*
* Force iterators to be simple names, expressions, or numbers
*/
void
{
"invalid iterator: ");
}
}
/*
* Iterators on a declaration may only be implicit
*/
void
{
"explicit iterators disallowed "
"in declarations: ");
}
} else {
break;
}
}
}
void
{
switch (arglist->t) {
case T_NUM:
"parameter of within must be 0"
", \"infinity\" or a time value.");
break;
case T_NAME:
"parameter of within must be 0"
", \"infinity\" or a time value.");
break;
case T_LIST:
/*
* if two parameters, the left or min must be
* either T_NUM or T_TIMEVAL
*/
"first parameter of within must be"
" either a time value or zero.");
/*
* if two parameters, the right or max must
* be either T_NUM, T_NAME or T_TIMEVAL
*/
"second parameter of within must "
"be 0, \"infinity\" "
"or time value.");
/*
* if right or left is a T_NUM it must
* be zero
*/
"within parameter must be 0 or"
" a time value.");
!= 0ULL)
"within parameter must be 0 or"
" a time value.");
/* if right is a T_NAME it must be "infinity" */
!= L_infinity)
"\"infinity\" is the only valid"
" name for within parameter.");
/*
* the first parameter [min] must not be greater
* than the second parameter [max].
*/
"the first value (min) of"
" within must be less than"
" the second (max) value");
break;
case T_TIMEVAL:
break; /* no restrictions on T_TIMEVAL */
default:
"parameter of within must be 0"
", \"infinity\" or a time value.");
}
"invalid first argument to call()");
"argument to fru() must be a path");
"argument to asru() must be a path");
} else {
"%s() must have paths or calls to "
}
} else {
"argument to is_on() must be a call to "
"fru() or asru()");
}
} else {
"argument to is_present() must be a call to "
"fru() or asru()");
}
} else {
"argument to is_type() must be a call to "
"fru() or asru()");
}
} else {
"confprop(): first argument must be a call to "
"fru() or asru(); "
"second argument must be a string");
}
"argument to payloadprop() must be a string");
"argument to envprop() must be a string");
} else
"possible platform-specific function: %s",
}
void
{
switch (np->t) {
case T_ASSIGN:
"assignment only allowed to globals (e.g. $a)");
break;
}
}
void
{
"pathless events not allowed: ");
}
}
/*
* check for properties that are required on declarations. This
* should be done after all declarations since they can be
* redeclared with a different set of properties.
*/
/*ARGSUSED*/
void
{
}